在Python/Django中使用拆分模型循环模块依赖



我理解如何分解模型,并且我理解为什么循环模块依赖关系会把事情搞砸,但是我遇到了一个问题,将模型分解成单独的文件似乎会导致循环依赖。下面是代码的一个摘录,我将用失败过程的回溯来跟踪它:

elearning/tasks.py

from celery.task import task
@task
def decompress(pk):
    from elearning.models import Elearning
    Elearning.objects.get(pk=pk).decompress()

elearning/models.py

from competency.models import CompetencyProduct
from core.helpers import ugc_elearning
from elearning.fields import ArchiveFileField
class Elearning(CompetencyProduct):
    archive = ArchiveFileField(upload_to=ugc_elearning)
    def decompress(self):
        import zipfile
        src = self.archive.path
        dst = src.replace(".zip","")
        print "Decompressing %s to %s" % (src, dst)
        zipfile.ZipFile(src).extractall(dst)

ecom/models/products.py

from django.db import models
from django.utils.translation import ugettext_lazy as _
from core.models import Slugable, Unique
from django_factory.models import Factory
from core.helpers import ugc_photos
class Product(Slugable, Unique, Factory):
    photo          = models.ImageField(upload_to=ugc_photos, width_field="photo_width", height_field="photo_height", blank=True)
    photo_width    = models.PositiveIntegerField(blank=True, null=True, default=0)
    photo_height   = models.PositiveIntegerField(blank=True, null=True, default=0)
    description    = models.TextField()
    price          = models.DecimalField(max_digits=16, decimal_places=2)
    created        = models.DateTimeField(auto_now_add=True)
    modified       = models.DateTimeField(auto_now=True)

ecom/models/__init__.py

from django.contrib.auth.models import User
from django.db import models
from ecom.models.products import Product, Credit, Subscription
from ecom.models.permissions import Permission
from ecom.models.transactions import Transaction, DebitTransaction, CreditTransaction, AwardTransaction, FinancialTransaction, PermissionTransaction, BundleTransaction

competency/models.py

from django.db import models
from django.utils.translation import ugettext_lazy as _
from core.models import Slugable, Unique
from ecom.models import Product
from rating.models import Rated
from trainer.models import Trainer
class Competency(Slugable, Unique):
    class Meta:
        verbose_name = _("Competency")
        verbose_name_plural = _("Competencies")
    description = models.TextField()

class CompetencyProduct(Product, Rated):
    class Meta:
        verbose_name = _("Product")
        verbose_name_plural = _("Products")
    release  = models.DateField(auto_now_add=True)
    trainers     = models.ManyToManyField(Trainer)
    competencies = models.ManyToManyField(Competency, related_name="provided_by")
    requirements = models.ManyToManyField(Competency, related_name="required_for", blank=True, null=True)
    forsale      = models.BooleanField("For Sale", default=True)

ecom/models/permissions.py

from django.contrib.auth.models import User
from django.db import models
from django.utils.translation import ugettext_lazy as _
from treebeard.mp_tree import MP_Node
from collective.models import Collective
from course.models import Course
from ecom.models.products import Product
class Permission(MP_Node):
    class Meta:
        app_label = "ecom"
    product      = models.ForeignKey(Product, related_name="permissions")
    user         = models.ForeignKey(User, related_name="permissions")
    collective   = models.ForeignKey(Collective, null=True)
    course       = models.ForeignKey(Course, null=True)
    redistribute = models.BooleanField(default=False)
    created      = models.DateTimeField(auto_now_add=True)
    modified     = models.DateTimeField(auto_now=True)
    accessed     = models.DateTimeField(auto_now=True)

course/models.py

from django.db import models
from django.utils.translation import ugettext_lazy as _
from competency.models import CompetencyProduct
from ecom.models import Product
from rating.models import Rated
class Chapter(models.Model):
    seq  = models.PositiveIntegerField(name="Sequence", help_text="Chapter number")
    name = models.CharField(max_length=128)
    note = models.CharField(max_length=128)

class Course(Product, Rated):
    level    = models.PositiveIntegerField(choices=CompetencyProduct.LEVELS)
    chapters = models.ManyToManyField(Chapter)

class Bundle(models.Model):
    class Meta:
        unique_together = (("product", "chapter"),)
    product = models.ForeignKey(Product, related_name="bundles")
    chapter = models.ForeignKey(Chapter, related_name="bundles")
    amount  = models.PositiveIntegerField()
    seq     = models.PositiveIntegerField(name="Sequence", default=1)

从我所看到的,这里没有显式的循环递归,除了__init__.py中所需的引用,这似乎是在我的代码中发生的事情。下面是回溯:

  File "/path/to/project/virtualenv/lib/python2.6/site-packages/celery/execute/trace.py", line 47, in trace
    return cls(states.SUCCESS, retval=fun(*args, **kwargs))
  File "/path/to/project/virtualenv/lib/python2.6/site-packages/celery/app/task/__init__.py", line 247, in __call__
    return self.run(*args, **kwargs)
  File "/path/to/project/virtualenv/lib/python2.6/site-packages/celery/app/__init__.py", line 175, in run
    return fun(*args, **kwargs)
  File "/path/to/project/django/myproj/elearning/tasks.py", line 5, in decompress
    from elearning.models import Elearning
  File "/path/to/project/django/myproj/elearning/models.py", line 2, in <module>
    from competency.models import CompetencyProduct
  File "/path/to/project/django/myproj/competency/models.py", line 5, in <module>
    from ecom.models import Product
  File "/path/to/project/django/myproj/ecom/models/__init__.py", line 5, in <module>
    from ecom.models.permissions import Permission
  File "/path/to/project/django/myproj/ecom/models/permissions.py", line 8, in <module>
    from course.models import Course
  File "/path/to/project/django/myproj/course/models.py", line 4, in <module>
    from competency.models import CompetencyProduct
ImportError: cannot import name CompetencyProduct

我在这里要做的就是导入Elearning模型,它是CompetencyProduct的子类,然后是Product。然而,因为Product来自于更大的ecom/models.py的分解,ecom/__init__.py文件包含了所有分解模型的强制导入,包括Permission,它必须导入Course,而CompetencyProduct需要。

奇怪的是,整个网站运行完美。登录,购买,所有的一切。这个问题只发生在我试图在后台运行芹菜,并加载一个新任务,或者我试图使用Django环境运行shell脚本时。

我唯一的选择是从ecom应用程序中删除Permission,还是有更好,更智能的方法来处理这个问题?此外,如果您对我如何总体布局这个项目有任何意见,我将不胜感激。

您的问题是Permission导入Product,但两者都在ecom/models/__init__.py中导入。你应该找到一种方法,要么将这两个模型放在同一个文件中,要么将它们分开到两个应用程序中。

最新更新