2011-11-07 9 views
5

Capisco come suddividere i modelli e capisco perché le dipendenze dei moduli circolari fanno esplodere le cose, ma ho incontrato un problema in cui suddividere un modello in file separati sembra causare dipendenze circolari. Ecco un exerpt dal codice, e io seguire con il traceback dal processo in mancanza:Dipendenze dei moduli circolari in Python/Django con modelli split-up

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) 

Da quello che posso vedere, non c'è ricorsione circolare esplicita lui re, salvare i riferimenti richiesti in __init__.py che sembra essere dove le cose stanno esplodendo nel mio codice. Ecco il traceback:

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 

Tutto quello che sto cercando di fare qui è di importazione che Elearning modello, che è una sottoclasse di CompetencyProduct, e, a sua volta, Product. Tuttavia, dal momento che Product proviene da una rottura del più grande ecom/models.py, il file ecom/__init__.py contiene l'importazione obbligatoria di tutti i modelli interrotti, tra cui Permission che deve importare Course che richiede CompetencyProduct.

La cosa bizzarra è che l'intero sito funziona in modo impeccabile. Login, acquisti, tutto. Questo problema si verifica solo quando sto tentando di eseguire sedery in background e viene caricata una nuova attività o provo a eseguire uno script di shell usando l'ambiente Django.

È la mia unica opzione qui per rimuovere Permission dall'app ecom oppure esiste un modo migliore e più intelligente per gestirlo? Inoltre, tutti i commenti su come ho definito il progetto in generale sono apprezzati.

+0

Perché preoccuparsi di dare un esempio semplificato che * non * illustra il problema? Hai ragione; non esiste alcuna dipendenza circolare, ma * è * nel tuo codice attuale. Pubblica il tuo codice vero e proprio, puoi redigere qualsiasi cosa che non si applica, ma sarebbe di aiuto vedere come i tuoi file e modelli reali sono disposti nel tuo progetto. –

+0

Hai ragione. L'ho cambiato ora. –

risposta

3

Il tuo problema è che Permission importa Product, ma entrambi sono importati in ecom/models/__init__.py. Dovresti trovare un modo per avere questi due modelli nello stesso file o separarli in due app.

+0

Il fatto è che in realtà non ho * bisogno * di quei modelli in '__init __. Py', tranne che per syncdb per trovare i modelli e installarli.Credo che speravo di trovare un modo per evitare di mettere quelle importazioni in quel file in primo luogo. –

+1

Non possibile. Questo è l'unico modo per dividere i tuoi modelli in singoli file con Django. Queste importazioni devono essere in "__init __. Py", quindi in sostanza non è possibile eseguire l'importazione incrociata all'interno della stessa app. Se due modelli nella stessa app hanno bisogno l'uno dell'altro, devono essere nello stesso file. –

Problemi correlati