Django - problema de importação de modelo circular


116

Eu realmente não estou entendendo isso, então se alguém pudesse explicar como isso funciona, eu apreciaria muito. Tenho dois aplicativos, Contas e Tema ... aqui está minha lista de configurações:

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

Em contas, estou tentando fazer isso:

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)

E no meu modelo de tema:

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 está expulsando o seguinte erro:

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

É algum tipo de problema de importação circular? Tentei usar uma referência preguiçosa, mas também não parece funcionar!


1
Parece um problema com as importações circulares. Por que você precisa importar Accountdo módulo onde Themeestá definido?
Dominic Rodger

Desculpe, não colei meu modelo de Temas corretamente, atualizei minha postagem. Estou usando na aula de folha de estilo.
Hanpan

Respostas:


213

Remova a importação de Themee use o nome do modelo como uma string.

theme = models.ForeignKey('themes.Theme')

5
Na verdade, precisa ser 'themes.Theme', pois está em um aplicativo diferente.
Daniel Roseman

Ahh, funcionou, eu estava tentando apenas 'Theme' antes e não funcionou. Obrigado. Existe algum tipo de impacto no desempenho por fazer dessa maneira? Eu gostaria de manter minhas pesquisas não preguiçosas, se possível :)
Hanpan

@Daniel: Atualizado. @Hanpan: Um pequeno, sim. Mas apenas uma vez.
Ignacio Vazquez-Abrams

56

Upto Django 1.7:

Use a get_modelfunção django.db.modelsprojetada para importações de modelos preguiçosos:

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

No seu caso:

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

Agora você pode usar Theme

Para Django 1.7+:

from django.apps import apps
apps.get_model('app_label.model_name')

10
Use apps.get_model(app_label, model_name)ou apps.get_model('app_label.model_name') no Django 1.7+
phoibos

51

Algo que não vi mencionado em nenhum lugar com detalhes suficientes é como formular adequadamente a string dentro de ForeignKey ao fazer referência a um modelo em um aplicativo diferente. Esta string precisa ser app_label.model_name. E, o mais importante, app_labelnão é toda a linha no INSTALLED_APPS, mas apenas o último componente dela. Portanto, se o INSTALLED_APPS se parecer com isto:

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

em seguida, para incluir uma ForeignKey em um modelo em app2 em um modelo app1, você deve fazer:

app2_themodel = ForeignKey('app2.TheModel')

Passei um bom tempo tentando resolver um problema de importação circular (então não pude simplesmente from another.path.to.app2.models import TheModel) antes de me deparar com isso, google / SO não ajudou (todos os exemplos tinham caminhos de aplicativo de componente único), então espero que isso ajude outros novatos django.


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.