Django - Masalah impor model melingkar

116

Saya benar-benar tidak mengerti ini, jadi jika seseorang dapat menjelaskan cara kerjanya, saya akan sangat menghargainya. Saya memiliki dua aplikasi, Akun dan Tema ... berikut adalah daftar pengaturan saya:

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

Di akun, saya mencoba melakukan ini:

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)

Dan dalam model tema saya:

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 menendang kesalahan berikut:

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

Apakah ini semacam masalah impor melingkar? Saya sudah mencoba menggunakan referensi malas, tetapi tampaknya itu juga tidak berhasil!

Hanpan
sumber
1
Sepertinya masalah dengan impor melingkar. Mengapa Anda perlu mengimpor Accountdari modul di mana Themeditentukan?
Dominic Rodger
Maaf, saya tidak menempelkan model Tema saya dengan benar, saya telah memperbarui posting saya. Saya menggunakannya di kelas Stylesheet.
Hanpan

Jawaban:

213

Hapus impor Themedan gunakan nama model sebagai string.

theme = models.ForeignKey('themes.Theme')
Ignacio Vazquez-Abrams
sumber
5
Sebenarnya itu perlu 'themes.Theme', karena ada di aplikasi yang berbeda.
Daniel Roseman
Ahh, itu berhasil, saya hanya mencoba 'Tema' sebelumnya dan tidak berhasil. Terima kasih. Apakah ada kinerja yang bagus untuk melakukannya dengan cara ini? Saya ingin agar pencarian saya tidak malas jika memungkinkan :)
Hanpan
@Daniel: Diperbarui. @Hanpan: Yang kecil, ya. Tapi hanya sekali.
Ignacio Vazquez-Abrams
56

Hingga Django 1.7:

Gunakan get_modelfungsi django.db.modelsyang dirancang untuk impor model malas .:

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

Dalam kasus Anda:

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

Sekarang Anda bisa menggunakan Theme

Untuk Django 1.7+:

from django.apps import apps
apps.get_model('app_label.model_name')
Ranju R
sumber
10
Gunakan apps.get_model(app_label, model_name)atau apps.get_model('app_label.model_name') di Django 1.7+
phoibos
51

Sesuatu yang belum saya lihat disebutkan di mana pun dengan cukup detail adalah cara merumuskan string dengan benar di dalam ForeignKey saat mereferensikan model di aplikasi berbeda. String ini harus app_label.model_name. Dan, yang paling penting, app_labelbukan keseluruhan baris di INSTALLED_APPS, tetapi hanya komponen terakhirnya . Jadi jika INSTALLED_APPS Anda terlihat seperti ini:

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

lalu untuk menyertakan ForeignKey ke model di app2 dalam model app1, Anda harus melakukan:

app2_themodel = ForeignKey('app2.TheModel')

Saya menghabiskan waktu cukup lama untuk mencoba menyelesaikan masalah impor melingkar (jadi saya tidak bisa begitu saja from another.path.to.app2.models import TheModel) sebelum saya tersandung ke ini, google / SO tidak membantu (semua contoh memiliki jalur aplikasi komponen tunggal), jadi semoga ini akan membantu yang lain django pemula.

Bogatyr
sumber
40

Sejak Django 1.7 cara yang benar adalah pergi seperti ini:

from django.apps import apps

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

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

andilabs
sumber
5
Ada juga sintaks pintasan argumen tunggal: apps.get_model('your_app_name.YourModel')nyaman untuk digunakan di mapdll.
Taylor Edmiston