9

I've refactored my models files into a module - this way it's much easier to maintain the code since it has grown quite a bit.

The funny thing is though that it won't work for one of the classes that references another class that references the fist one in it's turn:

UPD: the cycling references are confusing python and this is what the problem is caused by. This is easy to fix when you only reference other models from your model definition. However, Picture has methods that reference paperType class and vice versa - how can this be fixed?

Here's class Picture:

from django.db import models
from django.utils import simplejson
from picviewer.models import Collection, ImageSizeRatio, printSize

class Picture(models.Model):
    name = models.TextField(null=False,blank=False,unique=False)
    collection = models.ForeignKey(Collection)
    popularity = models.IntegerField(default=0,unique=False)
    isPurchasable = models.BooleanField(default=False)
    allowBuyExclusive = models.BooleanField(default=False)
    basePrice = models.DecimalField(decimal_places=2,max_digits=8)
    imageSizeRatio = models.ForeignKey(ImageSizeRatio)
    imageThumbnail = models.FileField(upload_to='pictures')
    imagePreview = models.FileField(upload_to='pictures')
    imageSmall = models.FileField(upload_to='pictures')
    imageNormal = models.FileField(upload_to='pictures')
    imageLarge = models.FileField(upload_to='pictures')
    imageHuge = models.FileField(upload_to='pictures')
    allowedPrintSize = models.ManyToManyField(printSize)

Here is printSize class that it references - you see it calls Picture functions to do some math around pictures of specified printSize:

from django.db import models
from picviewer.models import paperType
from picviewer.models import Picture

class printSize (models.Model):
    name = models.CharField(null=False,blank=False,unique=True,max_length=60)
    width = models.IntegerField(null=False,blank=False)
    height = models.IntegerField(null=False,blank=False)
    allowedPaperType = models.ManyToManyField(paperType)
    #isActive = models.NullBooleanField(null=True, default=None)

    def json(self, picture_id, base_price):
        sizes_selector = printSize.objects.filter(picture__id = picture_id)
        sizes = list()
        for size in sizes_selector:
            papers = list()
            for paper in size.allowedPaperType.all():
                cost_for_paper = Picture.objects.get(id=picture_id).calculatePrice(paper.id,size.id)
                p = dict(id = paper.id,
                         name = paper.name,
                         description = paper.description,
                         price = paper.pricePerSqMeter.__str__(),
                         cost = "%.2f" % cost_for_paper)
                papers.append(p)
            s = dict(id = size.id,
                     name = size.name,
                     width = size.width,
                     height = size.height,
                     allowedPapers = papers)
            sizes.append(s)
        return sizes

now this is what I get in shell trying to import Picture:

>>> from picviewer.models import Picture
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "D:\~Sasha\eclipse_workspace\zavalen\picviewer\models\Picture.py", line 4, in <module>
    from picviewer.models import Collection, ImageSizeRatio, printSize
  File "D:\~Sasha\eclipse_workspace\zavalen\picviewer\models\printSize.py", line 4, in <module>
    from picviewer.models import Picture
ImportError: cannot import name Picture
>>>

can I cure this? :)

abolotnov
  • 4,282
  • 9
  • 56
  • 88
  • I guess python gets confused by the cyclic reference - but if they two need to use each other - is there a way to fix this? – abolotnov Apr 15 '11 at 10:24
  • Why do you have `null=True` on your `TextField`? http://docs.djangoproject.com/en/1.3/ref/models/fields/#null advises against it. – bradley.ayers Apr 15 '11 at 10:26

1 Answers1

30

To avoid cyclic imports, specify FK model as a string, e.g

collection = models.ForeignKey('Collection') # Collection is in the same module

or

collection = models.ForeignKey('myapp.Collection') # Collection is in another app
Dmitry Shevchenko
  • 31,814
  • 10
  • 56
  • 62
  • +1, beaten to it. See [the docs](http://docs.djangoproject.com/en/1.3/ref/models/fields/#module-django.db.models.fields.related) which explicitly mention this case. – Blair Apr 15 '11 at 10:35
  • it does work if only references to other models are in the model definition. how do I walk around referencing other models from the class' methods? – abolotnov Apr 15 '11 at 11:00
  • In the example you gave, you should be able to drop the ``from picviewer.models import Collection, ImageSizeRatio, printSize`` line from the Picture model, thus removing the cyclic reference. The printSize model should then import Picture with no problems. – Blair Apr 15 '11 at 11:08
  • yes, but my Picture class has def something(): return printSize().json(self.id,self.basePrice) - how do I go about this one? – abolotnov Apr 15 '11 at 11:15
  • 2
    Oh, OK. One option would be to import the module within the function rather than the whole file, e.g. ``def something(): from picviewer.models import printSize; return printSize().json(self.id, self.basePrice)``. There's probably other ways of doing this but its late and my brain isn't functioning that well. I'd suggest updating the question with sample functions to show exactly what you mean, and see what other suggestions appear. – Blair Apr 15 '11 at 11:39
  • This, I think, has worked out, Blair. I'm wondering why I haven't thought about this in the first place :) – abolotnov Apr 15 '11 at 12:05
  • I really love django but I think this is a bit messy. The strange thing is that you can do it in the interactive python shell? – Ward Aug 04 '13 at 11:38