2014-02-16 58 views
0

我目前正在研究一個Django庫來管理多個分辨率的圖像(django-multires),我堅持優化保留關係查詢。在我解釋這個問題之前,讓我試着解釋我想達到的目標。Django查詢沒有外鍵的反向關係

背景

的想法是存儲圖像的多種分辨率然而保持圖像路徑,而不是外鍵方面對原始圖像的引用。我認爲一個例子會更有意義:

# the goal is to store multiple resolutions for 'image' field 
class FooModel(models.Model): 
    image = MultiresImageField(...) 

# MultiresImage.source will be the identical to FooModel.image 
# so MultiresImage.source will act sort of like a foreign key 
class MultiresImage(models.Model): 
    source = models.ImageField(...) 
    ... 

使用這種方法,而不是使用一個外鍵(或通用外鍵)鏈接到源圖像允許多個MultiresImageField s添加到源模型:

class FooModel(models.Model): 
    image = MultiresImageField(...) 
    image2 = MultiresImageField(...) 

現在讓我們說,你需要得到源模型中對圖像領域的所有不同的分辨率:

foo = FooModel(...) 
foo.image.get_all_multires_images() 
# which behind the scenes will do something similar to 
return MultiresImage.objects.filter(source=foo.image.name) 

直到你需要牛逼效果很好Ø查詢多個FooModel情況下,在這種情況下,每個模型實例,我不得不做一個數據庫查詢,以獲取該模型的所有決議:

sources = FooModel.objects.filter(...) 
for source in sources: 
    # this incurs a db query 
    foo.image.get_all_multires_images() 

通常我會用prefetch_related但是做性能優化在這裏我可以因爲我的multires模型沒有源模型的外鍵,因此源模型中不存在反向關係。

問題

所以我的問題是如何能在上面的查詢進行優化?

目前的一些想法

  • 因爲我想提出一個自定義模型領域,我可以用contribute_to_class手動添加到源模型的反向關係,但我想不通怎麼樣?
  • 另一個雖然是使用Prefetch API Django>=1.7但我不知道如何使這項工作以及。
+0

沒有關於您的自定義MuliResImageField的更多信息,很難給您適當的建議。無論如何我不明白的是:爲什麼你不能使用簡單的ForeignKey。例如。 image = models.ForeignKey(MultiResImage);圖像2 = models.ForeignKey(MultiResImage)。 – schacki

+0

我想'MultiresImageField'與常規Django圖像字段向後兼容。您可以在github上看到'MultiresImageField'的當前代碼,但是我不認爲這有助於解決這個查詢問題。 – miki725

回答

0

最簡單的,但可能不是最優雅的解決辦法是寫一種輔助類的:

def prefetch_related_images(image_queryset): 
    multires_images = MultiresImage.objects.filter(source__in=[image.name for image in image_queryset ]) 
    for image in image_queryset: 
     image.multires_images = [] 
     for multires_image in multires_images: 
      if multires_image.source == image.name: 
       image.multires_images.append(multires_image) 

和幸福,更優雅的解決方案是沿上contribute_to_class你的思想的線條。你爲什麼不嘗試一些像普通的關係:

class MultiresImage(models.Model): 
    source = models.ImageField(...) 
    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    image_target= GenericForeignKey('content_type', 'object_id') 

,然後修改contribute_to_class這樣的:

def contribute_to_class(self, cls, name): 
    """ 
    Attached necessary garbage collection signals. 
    """ 
    super(MultiresImageField, self).contribute_to_class(cls, name) 

    setattr(cls,'%_source', GenericRelation(MultiresImage) 

然後處理管理通過信號的關係的細節(因爲你已經做)。

+0

這大致就是我現在所做的。我希望找到一種方法來連接到Django的API。 Thanx無論如何。 – miki725