Entiendo cómo dividir modelos, y entiendo por qué las dependencias de módulos circulares explotan las cosas, pero me he encontrado con un problema donde dividir un modelo en archivos separados parece estar causando dependencias circulares. He aquí un extracto del código, y voy a seguir con el rastreo del proceso en su defecto:Dependencias de módulos circulares en Python/Django con modelos divididos
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)
Por lo que puedo ver, no hay recursividad circular explícita él re, guarde para las referencias requeridas en __init__.py
que parece estar donde las cosas están explotando en mi código. Aquí está el rastreo:
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
Todo lo que estoy tratando de hacer aquí es que la importación Elearning
modelo, que es una subclase de CompetencyProduct
, ya su vez, Product
. Sin embargo, debido a que Product
proviene de una división del mayor ecom/models.py
, el archivo ecom/__init__.py
contiene la importación obligatoria de todos los modelos descompuestos, incluido Permission
que tiene que importar Course
que requiere CompetencyProduct
.
Lo loco es que todo el sitio funciona correctamente. Logins, compras, todo. Este problema solo ocurre cuando intento ejecutar el apio en segundo plano y se carga una nueva tarea o trato de ejecutar un script de shell usando el entorno de Django.
¿Es mi única opción aquí eliminar Permission
de la aplicación ecom
, o hay una manera mejor y más inteligente de manejar esto? Además, cualquier comentario sobre cómo he presentado el proyecto en general es apreciado.
¿Por qué molestarse en dar un ejemplo simplificado que * no * ilustra el problema? Tienes razón; no hay una dependencia circular allí, pero * está * en su código real. Publique el código actual, puede redactar todo lo que no corresponda, pero sería útil ver cómo se presentan sus archivos y modelos reales en su proyecto. –
Tienes razón. Lo he cambiado ahora. –