Эффективность отношений между родителями и детьми - PullRequest
1 голос
/ 14 марта 2012

У меня есть поле изображения в одном из моих приложений Django, но я хочу иметь возможность хранить ревизии изображения, чтобы позволить мне отображать список в порядке ревизии.Является ли лучший способ сделать это, чтобы хранить изображения отдельно, а затем иметь «родительское» отношение ForeignKey к родительским изображениям?Например:

class Image(models.Model):
    name = models.CharField(max_length=50)
    parent = models.ForeignKey(Image, null=True)
    image = models.ImageField(upload_to='images')

Если родительский элемент отсутствует (null=True), в изображении не должно быть ревизий.У каждого объекта может быть только один родительский и один дочерний, но количество слоев потенциально не ограничено.

Я не знаю, можно ли обойти несколько слоев потомков без генерации значительного количества SQL-запросов, чтосделать приложение очень неэффективным.Каков наилучший способ представить это в терминах объектов Django?Лучше ли иметь отдельный объект 'ImageRevision', например, для обработки слоев?

Спасибо

Ответы [ 2 ]

1 голос
/ 14 марта 2012

Я вижу два способа сделать это эффективно:

  1. Свяжите Image с моделью, на которой он используется, что позволяет использовать один ко многим для изображения:

    class Image(models.Model):
        obj = models.ForeignKey(MyModel, related_name='images')
        name = models.CharField(max_length=50)
        image = models.ImageField(upload_to='images')
        created = models.DateTimeField(auto_now_add=True)
    
        class Meta:
            ordering = ['-created']
            get_latest_by = 'created'
    

    Затем вы можете получить последнюю версию, выполнив:

    my_model_instance.images.latest()
    
  2. Создайте модель ImageRevision, как вы упомянули, и привяжите ее к Image.

    class Image(models.Model):
        name = models.CharField(max_length=50)
    
    class ImageRevision(models.Model):
        parent = models.ForeignKey(Image, related_name='revisions')
        image = models.ImageField(upload_to='images')
        created = models.DateTimeField(auto_now_add=True)
    
        class Meta:
            ordering = ['-created']
            get_latest_by = 'created'
    

    Затем вы можете получить последнюю версию с помощью:

    my_model_instance.image.revisions.latest()
    

Второй метод включает дополнительный запрос для дополнительных отношений (хотя вы должны быть в состоянии смягчить это при разумном использовании select_related), но он имеет преимущество, заключающееся в возможности использования с несколькими различными моделями, тогда как первый метод привязывает Image по своей природе к одной модели.

0 голосов
/ 14 марта 2012

В этом случае я бы, скорее всего, пошел с отдельным объектом ревизий.Удалите родительское поле из изображения (кроме этого, это будет OneToOne, а не ForeignKey, чтобы запретить нескольким дочерним элементам иметь одного родителя).Таким образом, у вас будет объект Image с именем и объект ревизии с ImageField, например:

class Image(models.Model):
    name = models.CharField(max_length=50)
    def __unicode__(self):
        return self.name

class Revision(models.Model):
    image = models.ForeignKey(Image)
    revision_number = models.IntegerField()
    file = models.ImageField(upload_to='images')

Обход, тогда не требуется рекурсия по цепочке.Примерно так:

for i in Image.objects.all():
    print i.name
    for r in Revision.objects.filter(image=i).order_by('revision_number'):
        print "rev. " + str(r.revision_number) + " " str(r.file)

Вот как я бы с этим справился, по крайней мере.

Приветствия

...