Django - проблема с импортом круговой модели

116

Я действительно не понимаю этого, поэтому, если бы кто-нибудь мог объяснить, как это работает, я был бы очень признателен. У меня есть два приложения, Аккаунты и Тема ... вот мой список настроек:

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

В аккаунтах я пытаюсь это сделать:

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)

И в моей модели темы:

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 выдает следующую ошибку:

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

Это какая-то проблема с циклическим импортом? Я пробовал использовать ленивую ссылку, но это тоже не работает!

Hanpan
источник
1
Это похоже на проблему с циклическим импортом. Зачем нужно импортировать Accountиз модуля, где Themeопределено?
Доминик Роджер
Извините, я неправильно вставил свою модель тем, я обновил свой пост. Я использую его в классе таблиц стилей.
Ханпан

Ответы:

213

Удалите импорт Themeи используйте вместо этого название модели в виде строки.

theme = models.ForeignKey('themes.Theme')
Игнасио Васкес-Абрамс
источник
5
На самом деле так и должно быть 'themes.Theme', потому что это в другом приложении.
Дэниел Роузман,
Ах, это сработало, раньше я пробовал просто "Theme", и это не сработало. Спасибо. Есть ли какое-то снижение производительности, если это будет сделано таким образом? Я бы хотел, чтобы мои поиски не были ленивыми, если это возможно :)
Ханпан
@ Даниэль: Обновлено. @Hanpan: Да, маленький. Но только один раз.
Игнасио Васкес-Абрамс,
56

До Django 1.7:

Используйте get_modelфункцию, django.db.modelsкоторая предназначена для ленивого импорта моделей:

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

В твоем случае:

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

Теперь вы можете использовать Theme

Для Django 1.7+:

from django.apps import apps
apps.get_model('app_label.model_name')
Ранджу Р
источник
10
Используйте apps.get_model(app_label, model_name)or apps.get_model('app_label.model_name') в Django 1.7+
phoibos
51

То, что я нигде не упоминал достаточно подробно, - это то, как правильно сформулировать строку внутри ForeignKey при ссылке на модель в другом приложении. Эта строка должна быть app_label.model_name. И, что очень важно, app_labelэто не вся строка в INSTALLED_APPS, а только ее последний компонент . Итак, если ваш INSTALLED_APPS выглядит так:

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

затем, чтобы включить ForeignKey в модель в app2 в модели app1, вы должны сделать:

app2_themodel = ForeignKey('app2.TheModel')

Я довольно долго пытался решить проблему с циклическим импортом (поэтому я просто не мог from another.path.to.app2.models import TheModel), прежде чем наткнулся на это, google / SO не помог (во всех примерах были пути к приложениям с одним компонентом), поэтому, надеюсь, это поможет другим django для новичков.

Богатырь
источник
40

Поскольку Django 1.7 правильный путь - это сделать так:

from django.apps import apps

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

См. Https://docs.djangoproject.com/ja/1.9/ref/applications/#django.apps.apps.get_model

andilabs
источник
5
Также есть сокращенный синтаксис с одним аргументом: apps.get_model('your_app_name.YourModel')удобный для использования в и mapт. Д.
Тейлор