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.