Python / Django中的循环模块依赖关系与拆分模型

时间:2011-11-07 15:03:58

标签: python django

我理解如何分解模型,并且我理解为什么循环模块依赖性会搞砸,但是我遇到了一个问题,即将模型分解为单独的文件似乎会导致循环依赖。这是代码中的一个exerpt,我将跟踪失败过程中的追溯:

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的{​​{1}}。

古怪的是整个网站完美运作。登录,购买,一切。只有在我尝试在后台运行celery并加载新任务或尝试使用Django环境运行shell脚本时才会出现此问题。

此处我唯一的选择是从CompetencyProduct应用中移除Permission,还是有更好,更智能的方法来处理此问题?此外,对我如何制定项目的任何评论都表示赞赏。

1 个答案:

答案 0 :(得分:3)

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