2013-06-30 36 views
7

我在Django(使用Postgres)中有以下模型模式。Django:快速檢索manyToMany字段的ID

class A(Models.model): 
    related = models.ManyToManyField("self", null=True) 

給出的一個QuerySet,我想在查詢集儘可能快地恢復一個字典映射的A每個實例的id開發它related實例列表越好。

我肯定可以迭代每個A並查詢相關字段,但是有沒有更優化的方法?

+0

你有沒有得到這個解決方案? – cazgp

回答

8

根據你有三個實例。您可以使用values_list方法來檢索結果,並從此結果中獲取related實例的ID。 我使用pk字段做我的過濾器,因爲我不知道你的方案,但你可以使用任何東西,只需要一個QuerySet

>>> result = A.objects.filter(pk=1) 
>>> result.values('related__id') 
[{'id': 2}, {'id': 3}] 
>>> result.values_list('related__id') 
[(2,), (3,)] 
>>> result.values_list('related__id', flat=True) 
[2, 3] 
+1

這就是我一直在做的,但問題是我需要過濾多個'pk'(例如'A.objects.filter(pk__in = [1,2,6])'')。我想要一個列表清單,其中第n個內部列表像這裏的'values_list',但對應於第n個'pk'。 –

+0

如果您已經有單個模型實例,您也可以執行instance.related.values('id',flat = True)。 – alexcasalboni

0

你可以得到非常接近這樣的:

qs = A.objects.prefetch_related(Prefetch(
         'related', 
         queryset=A.objects.only('pk'), 
         to_attr='related_insts')).in_bulk(my_list_of_pks) 

這會給出一個映射,從當前對象的實例本身PKS,這樣你就可以遍歷如下:

for pk, inst in qs.iteritems(): 
    related_ids = (related.pk for related in inst.related_insts) 

或者給出一個實例,你可以做一個快速查找,像這樣:

related_ids = (related.pk for related in qs[instance.pk]). 

由於您特別請求了字典,因此此方法會將實例ID映射到相關的ID(間接)。如果你不這樣做的查找,您可能要改爲以下內容:

qs = A.objects.prefetch_related(Prefetch(
     'related', 
     queryset=A.objects.only('pk'), 
     to_attr='related_insts')).filter(pk__in=my_list_of_pks) 
for inst in qs: 
    related_ids = (related.pk for related in inst.related_insts) 

您可能會注意到使用only的只從DB拉PKS。有一個open ticket允許在預取查詢中使用values和(我假設)values_list。這將允許您執行以下操作。

qs = A.objects.prefetch_related(Prefetch(
     'related', 
     queryset=A.objects.values_list('pk', flat=True), 
     to_attr='related_ids')).filter(pk__in=my_list_of_pks) 
for inst in qs: 
    related_ids = inst.related_ids 

你當然可以進一步優化,例如通過在主查詢集使用qs.only('related_insts'),但要確保你沒有做任何與這些instances--他們基本上只是昂貴的容器來保存你的related_ids。

我相信這是現在最好的(沒有自定義查詢)。爲了得到你想要什麼,還需要兩兩件事:

  1. 上述特徵實現
  2. values_list由像它的註解與預取to_attr工作。

有了這兩樣東西(並繼續上面的例子),你可以做到以下幾點得到正是你要求:

d = qs.values_list('related_ids', flat=True).in_bulk() 
for pk, related_pks in d: 
    print 'Containing Objects %s' % pk 
    print 'Related objects %s' % related_pks 
# And lookups 
print 'Object %d has related objects %s' % (20, d[20]) 

我已經離開了一些細節解釋的事情,但它應該從文檔中很清楚。如果您需要澄清,請不要猶豫!