Django не может импортировать свои собственные модели

У меня есть несколько приложений Django, все в одном каталоге проекта. В каждом приложении есть файл models.py с кучей моделей. Я без проблем импортировал модели из одного приложения в другое, в частности, для создания новой модели с полем внешнего ключа, указывающим на модель в другом приложении. Пока нет проблем.

Решил создать новую модель. Он имеет 4 поля ForeignKey, каждое из которых указывает на другую модель в другом приложении. Простой. Однако, когда я пытаюсь использовать south для переноса схемы в базу данных, он сообщает мне, что не может импортировать мои модели. Почему?!

Итак, это моя новая модель:

class Action_Tracker(models.Model):
    dateOfAction = models.DateField(verbose_name = 'Date of Action')
    user = models.CharField(max_length=30, verbose_name = 'Action completed by')
    sys = models.ForeignKey(System, verbose_name='For System')
    wo = models.ForeignKey(Work_Order, verbose_name='Associated WO', blank=True, null=True)
    inv = models.ForeignKey(Invoice, verbose_name = 'Associated Invoice', blank=True, null=True)
    subdT = models.ForeignKey(SUBD_Tracker, verbose_name = 'Associated SUBD Tracker', blank=True, null=True)
    notes = models.TextField(verbose_name='Notes of Action', blank=True, null=True)

    def __unicode__(self):
        return u'%s -- %s' % (self.dateOfAction, self.notes)

    class Meta:
        orering = ['dateOfAction']

В верхней части этого файла models.py у меня есть следующий импорт:

from django.db import models
from django.forms import ModelForm, forms
from staff.models import Employee, Position
from work_orders.models import Work_Order, SUBD_Tracker
from invoices.models import Invoice

Насколько я могу судить, я импортирую их правильно. Однако, когда я пытаюсь выполнить миграцию схемы, я получаю следующую ошибку:

File "/srv/www/cpm/../cpm/systems/models.py", line 4, in <module>
  from work_orders.models import Work_Order, SUBD_Tracker
File "/srv/www/cpm/work_orders/models.py", line 5, in <module>
  from systems.models import System
File "/srv/www/cpm/systems/models.py", line 4, in <module>
  from work_orders.models import Work_Order, SUBD_Tracker
ImportError: cannot import name Work_Order

Любая идея, что здесь происходит не так ??

Спасибо

ИЗМЕНИТЬ — по запросу

Я публикую код work_order models.py по запросу (по крайней мере, соответствующие части):

from django.db import models
from django.forms import ModelForm, forms
from django import forms
from products.models import Product
from systems.models import System
from labour.models import Labour_Costs
from staff.models import Employee
from datetime import date
import datetime

class Work_Order(models.Model):
    IS_COMPLETE_CHOICES = (
        ('Y', 'Yes'),
        ('N', 'No'),
    )

    INVOICE_CREATED_CHOICES = (
        ('Y', 'Yes, mark WO complete and generate invoice (if applicable)'),
        ('N', 'No, just save these changes'),
    )

    WO_TYPE_CHOICES = (
        ('M', 'Mechanical'),
        ('I', 'Install'),
        ('S', 'Show'),
        ('R', 'Service'),
        ('B', 'Blow down'),
        ('U', 'Start up'),
    )

    woID = models.CharField(max_length = 25, primary_key = True, verbose_name = 'Work Order ID')
    woType = models.CharField(max_length = 2, verbose_name = 'WO Type', default='R', choices = WO_TYPE_CHOICES)
    systemID = models.ForeignKey(System, verbose_name = 'System ID')
    notesToCrew = models.TextField(blank = True, null = True, verbose_name = 'Notes to Crew')
    dateWOCreated = models.DateField(blank = True, null = True, default=datetime.date.today(), verbose_name = 'Date Created')
    dateWORequired = models.DateField(blank = True, null = True, verbose_name = 'Date Required')
    dateCompleted = models.DateField(blank = True, null = True, verbose_name = 'Date Completed')
    numDays = models.DecimalField(max_digits = 3, decimal_places = 0, verbose_name = 'Number of Days to Complete', blank = True, null = True)
    numHours = models.DecimalField(max_digits = 3, decimal_places = 2, verbose_name = 'Number of Hours to Complete', blank = True, null = True)
    isComplete = models.CharField (max_length = 3, default = 'N', verbose_name = 'Set WO as Completed?', choices = IS_COMPLETE_CHOICES)
    isScheduled = models.CharField (max_length = 3, default = 'N', verbose_name = 'Is WO scheduled?', choices = IS_COMPLETE_CHOICES)
    isReqSoon = models.BooleanField(default=False, verbose_name='Is WO Required soon') #This flag will be set in a function to indicate that the WO is reqd within the current week/few days, whatever
    problemDescription = models.TextField(verbose_name = 'Problem Description', blank = True, null = True)
    resolution = models.TextField(verbose_name = 'Resolution', blank = True, null = True)
    serviceFromBD = models.TextField(verbose_name = 'Service issues noticed', blank = True, null = True)
    serviceFromBDEstTime = models.DecimalField(max_digits = 3, decimal_places = 2, verbose_name = 'Est. Time to Repair', blank = True, null = True)
    numWorkers = models.DecimalField(max_digits = 3, default=1, decimal_places = 0, verbose_name = 'Number of Workers Required', blank = True, null = True)
    invoiceCreated = models.CharField (max_length = 3, default = 'N', verbose_name = 'Generate Invoice?', choices = INVOICE_CREATED_CHOICES)

    def __unicode__(self):
        return u'%s - %s' % (self.woID, self.systemID.systemAddress)

    class Meta:
        ordering = ['woID']


class SUBD_Tracker(models.Model):
    SUBD_CHOICES = (
        ('U', 'Startup'),
        ('B', 'Blowdown'),
    )

    sys = models.ForeignKey(System, verbose_name = 'Related System')
    subd = models.CharField(max_length=1, verbose_name = 'SU or BD', choices = SUBD_CHOICES)
    ssn = models.CharField(max_length=5, verbose_name = 'Season')
    approved = models.BooleanField(verbose_name = 'Approved', default = False)
    declined = models.BooleanField(verbose_name = 'Declined', default = False)
    cancelled = models.BooleanField(verbose_name = 'Cancel', default = False)
    firstNoticeSent = models.BooleanField(verbose_name = 'First Notice Sent?', default = False)
    secondNoticeSent = models.BooleanField(verbose_name = 'Second Notice Sent?', default = False)
    wo = models.ForeignKey(Work_Order, verbose_name = 'Related WO', blank = True, null = True)

    def __unicode__(self):
        if self.subd == 'U':
            return u'%s: Startup - %s' % (self.sys, self.ssn)
        else:
            return u'%s: Blowdown - %s' % (self.sys, self.ssn)

    class Meta:
        ordering = ['sys']

person Garfonzo    schedule 20.10.2011    source источник
comment
Можете ли вы опубликовать код work_orders.models? Похоже, это может быть что-то вроде кругового импорта.   -  person Jason Goldstein    schedule 21.10.2011
comment
Это именно то, о чем я думал. Я просматривал свой код весь день, и циклический импорт начал приходить мне в голову. выложу код...   -  person Garfonzo    schedule 21.10.2011


Ответы (1)


Если вы прочитаете документацию по ForeignKey, вы увидите что первый аргумент может быть строкой. Это позволяет вам создавать свои внешние ключи без необходимости импорта, обходя проблему циклической ссылки.

Таким образом, ваша модель станет:

class Action_Tracker(models.Model):
    dateOfAction = models.DateField(verbose_name = 'Date of Action')
    user = models.CharField(max_length=30, verbose_name = 'Action completed by')
    sys = models.ForeignKey('systems.System', verbose_name='For System')
    wo = models.ForeignKey('work_orders.Work_Order', verbose_name='Associated WO', blank=True, null=True)
    inv = models.ForeignKey('invoices.Invoice', verbose_name = 'Associated Invoice', blank=True, null=True)
    subdT = models.ForeignKey('work_orders.SUBD_Tracker', verbose_name = 'Associated SUBD Tracker', blank=True, null=True)
    notes = models.TextField(verbose_name='Notes of Action', blank=True, null=True)

    def __unicode__(self):
        return u'%s -- %s' % (self.dateOfAction, self.notes)

    class Meta:
        ordering = ['dateOfAction']

Никаких заявлений об импорте не требуется!

person Evan Brumley    schedule 21.10.2011
comment
Великолепно! Я попробую это сегодня вечером. Спасибо - person Garfonzo; 21.10.2011
comment
Хорошо, это фантастика. Спасибо - это сработало как шарм. Кроме того, меньше дерьма в верхней части моего файла. Я мог бы просто продолжить и очистить все мои другие файлы models.py таким же образом. - person Garfonzo; 21.10.2011
comment
а если я хочу его импортировать не для объявления полей, а для простого использования в каких-то методах модели (чтобы Objec получал, выбирал, создавал и тд?) - person Ivan Borshchov; 25.06.2015
comment
@user3479125 user3479125 - просто импортируйте во время выполнения, поместив оператор импорта в метод модели. Это следует делать редко, так как это часто является признаком того, что ваша логика может быть лучше размещена в представлении или форме. Кроме того, не забывайте использовать связанные менеджеры — гораздо лучше использовать post.comments.create(...), чем Comment.objects.create(post=self, ...). - person Evan Brumley; 26.06.2015
comment
Спасибо! post.comments.создайте мне обновку, возможно в большинстве случаев теперь я буду работать с родственными моделями без импорта. (Я не думаю, что это хорошая идея - вставлять представления или формировать некоторый код, связанный с certian моделью и некоторыми моделями, связанными с ней). - person Ivan Borshchov; 26.06.2015