Django - Problème d'importation de modèle circulaire

116

Je ne comprends vraiment pas cela, donc si quelqu'un pouvait expliquer comment cela fonctionne, je l'apprécierais beaucoup. J'ai deux applications, Comptes et Thème ... voici ma liste de paramètres:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'accounts',
    'themes',
)

Dans les comptes, j'essaye de faire ceci:

from themes.models import Theme

class Account(models.Model):
    ACTIVE_STATUS = 1
    DEACTIVE_STATUS = 2
    ARCHIVE_STATUS = 3
    STATUS_CHOICES = (
        (ACTIVE_STATUS, ('Active')),
        (DEACTIVE_STATUS, ('Deactive')),
        (ARCHIVE_STATUS, ('Archived')),
    )

    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=250)
    slug = models.SlugField(unique=True, verbose_name='URL Slug')
    status = models.IntegerField(choices=STATUS_CHOICES, default=ACTIVE_STATUS, max_length=1)
    owner = models.ForeignKey(User)
    enable_comments = models.BooleanField(default=True)
    theme = models.ForeignKey(Theme)
    date_created = models.DateTimeField(default=datetime.now)

Et dans mon modèle de thème:

class Theme(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=250)
    slug = models.SlugField(unique=True, verbose_name='URL Slug')
    date_created = models.DateTimeField(default=datetime.now)

class Stylesheet(models.Model):
    id = models.AutoField(primary_key=True)
    account = models.ForeignKey(Account)
    date_created = models.DateTimeField(default=datetime.now)
    content = models.TextField()

Django supprime l'erreur suivante:

from themes.models import Theme
ImportError: cannot import name Theme

S'agit-il d'une sorte de problème d'importation circulaire? J'ai essayé d'utiliser une référence paresseuse, mais cela ne semble pas non plus fonctionner!

Hanpan
la source
1
Cela ressemble à un problème avec les importations circulaires. Pourquoi avez-vous besoin d'importer à Accountpartir du module où Themeest défini?
Dominic Rodger
Désolé, je n'ai pas collé correctement mon modèle de thèmes, j'ai mis à jour mon message. Je l'utilise dans la classe Stylesheet.
Hanpan

Réponses:

213

Supprimez l'importation Themeet utilisez le nom du modèle comme chaîne à la place.

theme = models.ForeignKey('themes.Theme')
Ignacio Vazquez-Abrams
la source
5
En fait, cela doit être 'themes.Theme', car c'est dans une application différente.
Daniel Roseman
Ahh, ça a marché, j'essayais juste "Thème" avant et ça n'a pas marché. Merci. Y a-t-il une sorte de succès de performance pour le faire de cette façon? Je voudrais garder mes recherches non paresseuses si possible :)
Hanpan
@Daniel: Mis à jour. @Hanpan: Un petit, oui. Mais une seule fois.
Ignacio Vazquez-Abrams
56

Jusqu'à Django 1.7:

Utilisez la get_modelfonction à partir de django.db.modelslaquelle est conçue pour les importations de modèles paresseux:

from django.db.models import get_model
MyModel = get_model('app_name', 'ModelName')

Dans ton cas:

from django.db.models import get_model
Theme = get_model('themes', 'Theme')

Maintenant vous pouvez utiliser Theme

Pour Django 1.7+:

from django.apps import apps
apps.get_model('app_label.model_name')
Ranju R
la source
10
Utiliser apps.get_model(app_label, model_name)ou apps.get_model('app_label.model_name') dans Django 1.7+
phoibos
51

Quelque chose que je n'ai vu mentionné nulle part avec suffisamment de détails est de savoir comment formuler correctement la chaîne à l'intérieur de ForeignKey lors du référencement d'un modèle dans une application différente. Cette chaîne doit être app_label.model_name. Et, plus important encore, le app_labeln'est pas la ligne entière dans INSTALLED_APPS, mais seulement le dernier composant de celui-ci. Donc, si votre INSTALLED_APPS ressemble à ceci:

INSTALLED_APPS = (
...
    'path.to.app1',
    'another.path.to.app2'
)

puis pour inclure une ForeignKey à un modèle dans app2 dans un modèle app1, vous devez faire:

app2_themodel = ForeignKey('app2.TheModel')

J'ai passé assez de temps à essayer de résoudre un problème d'importation circulaire (donc je ne pouvais pas juste from another.path.to.app2.models import TheModel) avant de tomber dessus, google / SO ne m'aidait pas (tous les exemples avaient des chemins d'application à composant unique), donc j'espère que cela aidera les autres les débutants de django.

Bogatyr
la source
40

Depuis Django 1.7, la bonne manière est de procéder comme suit:

from django.apps import apps

YourModel = apps.get_model('your_app_name', 'YourModel')

Voir: https://docs.djangoproject.com/ja/1.9/ref/applications/#django.apps.apps.get_model

andilabs
la source
5
Il existe également une syntaxe de raccourci à argument unique: apps.get_model('your_app_name.YourModel')pratique pour une utilisation dans un mapetc.
Taylor Edmiston