2015-11-05 50 views
4

我以前曾與select_relatedprefetch_related工作,它的工作很好。Django避免使用prefetch_related進行額外查詢不起作用

我正在處理當前的項目,出於某種原因,我無法弄清楚爲什麼我的預取相關查詢不能正常工作,因此我得到了大量冗餘數據庫調用。

我的模型:

class User(models.Model): 
    user_extra_info = models.ManyToManyField(
     AppGeneralData, 
     through='UserExtraInfo', 
     null=True, 
     blank=True 
    ) 

class AppGeneralData(models.Model): 
    title = models.CharField(max_length=255) 
    type = models.PositiveSmallIntegerField(
     choices=GENERAL_DATA_TYPE 
    ) 

class UserExtraInfo(models.Model): 
    user = models.ForeignKey(settings.AUTH_USER_MODEL) 
    info_item = models.ForeignKey(AppGeneralData) 

的查詢集:

User.objects.all().prefetch_related(
    Prefetch(
     'userextrainfo_set', 
     queryset=UserExtraInfo.objects.select_related('info_item').all() 
    ) 
) 

問題

當遍歷查詢集並調用一個子查詢,它不取它來自緩存的查詢集:

for user in qs: 
    user.userextrainfo_set.filter(
     info_item__type=general_data_type 
    ).values_list(
     'info_item__title', flat=True 
    )) 

子查詢只在每次調用時進入數據庫,我不明白我缺少什麼。

謝謝。

回答

4

當您撥打filter()時,這將創建一個不同的查詢集,因此Django無法使用prefetch_related中的數據。

您可以將篩選器移動到Prefetch對象的查詢集中。

qs = User.objects.all().prefetch_related(
    Prefetch('userextrainfo_set', queryset=UserExtraInfo.objects.filter(
     info_item__type=general_data_type 
    ).select_related('info_item'), to_attr='general_userextrainfo') 
) 

然後在訪問查詢集中的相關項時不使用filter()

for user in qs: 
    user.general_userextrainfo.values_list('info_item__title', flat=True)) 
+0

你是正確的,「過濾器」重新評估該查詢,但運行user.extrainfo_set.values_list(「info_item__title」,扁= TRUE)也重新演算值爲對我來說。只有user.userextrainfo_set.all()或user.userextrainfo_set.all()存在纔會重新評估。看起來'values_list'也重新評估查詢 - 至少從我的測試中看起來如此。另外,在prefetch_related中使用過濾器並不能真正幫助我,因爲我需要根據循環內部不斷變化的值進行過濾。無論如何,我可以「過濾」用戶而不用重新評估這個用戶嗎? – OmriToptix

+0

您可以在Python中進行過濾和轉換爲值列表,例如'info.info_item.title for user.userextrainfo_set.all()if info.info_item.type == general_data_type]'。 – Alasdair

+0

是的,在這個SO看到了這個解決方案Post:http://stackoverflow.com/questions/12973929/why-does-djangos-prefetch-related-only-work-with-all-and-not-filter並結束了使用它。我會接受你的回答,儘管'values_list'在我的測試中重新評估了查詢。 – OmriToptix

相關問題