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

Dan*_*inn 6 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()
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

从我所看到的,这里没有明确的循环递归,除了所需的引用,__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
Run Code Online (Sandbox Code Playgroud)

我在这里尝试做的就是导入该Elearning模型,这是一个子类CompetencyProduct,反过来Product.然而,由于Product来自于大的破裂ecom/models.py,该ecom/__init__.py文件包含了所有断开的车型的强制性进口,包括Permission其中有进口Course需要CompetencyProduct.

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

我是唯一可以Permissionecom应用程序中删除的选项,还是有更好,更智能的方法来处理这个问题?此外,对我如何布置项目的任何评论都表示赞赏.

Chr*_*att 5

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

  • 不可能。这是使用 Django 将模型划分为单独文件的唯一方法。这些导入必须位于“__init__.py”中,因此本质上,您不能在同一应用程序中交叉导入。如果同一应用程序中的两个模型需要彼此,则它们需要位于同一文件中。 (3认同)