2011-07-31 45 views
16

我的模特之一特別複雜。當我嘗試在Django Admin中對其進行編輯時,它會執行1042個查詢並需要9秒的時間才能處理。如何強制Django Admin使用select_related?

我知道我可以用raw_id_fields取代一些下拉菜單,但我認爲更大的瓶頸是它沒有執行select_related()

我可以得到管理網站來做到這一點嗎?

回答

8

對於我的特殊模型,特別緩慢的方面是通過ForeignKeys進行顯示時使用的形式顯示,這不是使用select_related調用的,所以這是我要加快的部分。

通過相關Django的來源看,你在django/contrib/admin/options.py看到formfield_for_foreignkeys需要每個FK db_field並調用ForeignKey類的formfield方法,它是在Django/DB /模型/場/與/像定義的方法:

def formfield(self, **kwargs): 
    db = kwargs.pop('using', None) 
    defaults = { 
     'form_class': forms.ModelChoiceField, 
     'queryset': self.rel.to._default_manager.using(db).complex_filter(self.rel.limit_choices_to), 
     'to_field_name': self.rel.field_name, 
    } 
    defaults.update(kwargs) 
    return super(ForeignKey, self).formfield(**defaults) 

由此,我們看到如果我們提供db_fieldkwargs['queryset']我們可以定義將使用select_related(這可以由formfield_for_foreignkey提供)的自定義查詢集。

所以基本上我們想要做的是覆蓋admin.ModelAdminSelectRelatedModelAdmin,然後使我們的SelectRelatedModelAdmin子類的ModelAdmin代替admin.ModelAdmin

class SelectRelatedModelAdmin(admin.ModelAdmin): 
    def formfield_for_foreignkey(self, db_field, request, **kwargs): 
     if 'queryset' in kwargs: 
      kwargs['queryset'] = kwargs['queryset'].select_related() 
     else: 
      db = kwargs.pop('using', None) 
      kwargs['queryset'] = db_field.rel.to._default_manager.using(db).complex_filter(db_field.rel.limit_choices_to).select_related() 
     return super(SelectRelatedModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs) 

此代碼示例不包括管理Inline S或ManyToManyField S,或foreign_key在由readonly_fields或自定義select_related查詢調用的函數中遍歷,但類似的方法應該適用於這些情況。

+0

這可以通過'get_field_queryset'被簡化(雖然它是無證,因此可以在未來改變)。 –

25

雖然jimbob博士的回答是有道理的,但對於我的需要,我只需重寫get_queryset()方法即可選擇外鍵的外鍵。也許這可能對某人有幫助。

class MyModelAdmin(admin.ModelAdmin): 
    model = MyModel 
    ... 
    def get_queryset(self, request): 
     return super(MyModelAdmin, self).get_queryset(request).select_related(
      'foreign_key1', 'foreign_key2__fk2_foreign_key') 
+1

queryset已重命名爲[get_queryset](https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_queryset) – phoibos

+0

這似乎不起作用**更改**頁面。也就是說,表單仍然有數千個查詢來獲取相關的實例。這僅僅是我,還是這對他人有用? django == 1.11.3 –

16

你可以試試這個

class Foo(admin.ModelAdmin): 
    list_select_related = (
     'foreign_key1', 
     'foreign_key2', 
    ) 

https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_select_related

+2

不幸的是,我不認爲這解決了原始查詢。 「list_select_related」屬性用於管理員_listing_頁面,而不是對象_edit_頁面。當然,在我遇到同樣的問題時,使用列表相關設置不會加快編輯頁面,只有列表和選擇頁面。 –