Django - Problema de importación de modelo circular


116

Realmente no entiendo esto, así que si alguien pudiera explicar cómo funciona esto, lo agradecería mucho. Tengo dos aplicaciones, Cuentas y Tema ... aquí está mi lista de configuraciones:

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

En cuentas, estoy tratando de hacer esto:

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)

Y en mi modelo temático:

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á lanzando el siguiente error:

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

¿Es este algún tipo de problema de importación circular? Intenté usar una referencia perezosa, ¡pero eso tampoco parece funcionar!


1
Parece un problema con las importaciones circulares. ¿Por qué necesita importar Accountdesde el módulo donde Themeestá definido?
— Dominic Rodger

Lo siento, no pegué mi modelo de Temas correctamente, he actualizado mi publicación. Lo estoy usando en la clase de hoja de estilo.
— Hanpan

Respuestas:


213

Elimine la importación de Themey use el nombre del modelo como una cadena en su lugar.

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

5
En realidad, tiene que ser así 'themes.Theme', ya que está en una aplicación diferente.
— Daniel Roseman

Ahh, eso funcionó, estaba probando solo 'Tema' antes y no funcionó. Gracias. ¿Hay algún tipo de impacto en el rendimiento por hacerlo de esta manera? Me gustaría mantener mis búsquedas no perezosas si es posible :)
— Hanpan

@Daniel: actualizado. @Hanpan: Uno pequeño, sí. Pero solo una vez.
— Ignacio Vazquez-Abrams

56

Hasta Django 1.7:

Utilice la get_modelfunción django.db.modelsque está diseñada para las importaciones de modelos perezosos

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

En tu caso:

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

Ahora puedes usar Theme

Para Django 1.7+:

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

10
Usar apps.get_model(app_label, model_name)o apps.get_model('app_label.model_name') en Django 1.7+
— phoibos

51

Algo que no he visto mencionado en ninguna parte con suficiente detalle es cómo formular correctamente la cadena dentro de ForeignKey al hacer referencia a un modelo en una aplicación diferente. Esta cadena debe ser app_label.model_name. Y, lo que es más importante, app_labelno es la línea completa en INSTALLED_APPS, sino solo el último componente de la misma. Entonces, si su INSTALLED_APPS se ve así:

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

luego, para incluir una ForeignKey a un modelo en app2 en un modelo app1, debe hacer:

app2_themodel = ForeignKey('app2.TheModel')

Pasé bastante tiempo tratando de resolver un problema de importación circular (por lo que no pude simplemente from another.path.to.app2.models import TheModel) antes de tropezar con esto, google / SO no fue de ayuda (todos los ejemplos tenían rutas de aplicación de un solo componente), así que espero que esto ayude a otros novatos de django.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.