2011-03-03 225 views
0

Django的1.2.5 的Python:2.5.5Django管理list_display與外鍵古怪慢

我的運動模式的管理員列表剛剛消失很慢(5分鐘400條記錄)。它在一秒鐘之內迴歸,直到我們有400場比賽,50場奇數隊和2場運動。

我修復了一個可怕的方式,所以我想看看是否有人以前見過這個。我的應用看起來像這樣:

models: 

Sport(models.Model) 
    name 

Venue(models.Model) 
    name 

Team(models.Model) 
    name 

Fixture(models.Model) 
    date 
    sport = models.ForeignKey(Sport) 
    venue = models.ForeignKey(Venue) 

TeamFixture(Fixture) 
    team1 = models.ForeignKey(Team, related_name="Team 1") 
    team2 = models.ForeignKey(Team, related_name="Team 2") 


admin: 

TeamFixture_ModelAdmin (ModelAdmin) 
    list_display = ('date','sport','venue','team1','team2',) 

如果我從list_display中刪除任何外鍵,那麼它很快。只要我添加任何外鍵然後慢。

models: 

TeamFixture(Fixture) 
    team1 = models.ForeignKey(Team, related_name="Team 1") 
    team2 = models.ForeignKey(Team, related_name="Team 2") 
    sport_name = "" 
    venue_name = "" 
    team1_name = "" 
    team2_name = "" 

    def __init__(self, *args, **kwargs): 
     super(TeamFixture, self).__init__(*args, **kwargs) 

     self.sport_name = self.sport.name 
     self.venue_name = self.venue.name 
     self.team1_name = self.team1.name 
     self.team2_name = self.team2.name 

admin: 

TeamFixture_ModelAdmin (ModelAdmin) 
    list_display = ('date','sport_name','venue_name','team1_name','team2_name',) 

管理所有其他型號的罰款幾千上萬條記錄的時刻,並在實際的所有觀點:

我通過在模型初始化使用非外鍵,但計算它們所以此工程在固定它網站運行良好。

回答

3

我會尋找的第一件事是數據庫調用。如果您不應該那樣做,請安裝django-debug-toolbar。這個很棒的工具可以讓你檢查爲當前請求完成的所有sql查詢。我認爲有很多。如果你看他們,你會知道在哪裏尋找問題。

我自己遇到的一個問題是:當模型的__unicode__方法使用外鍵時,會導致每個實例有一個數據庫命中。我知道兩種方法來解決這個問題:

  • 使用select_related,這通常是你最好的選擇。
  • 使您的__unicode__返回一個靜態字符串並覆蓋save方法來相應地更新此字符串。
+0

此外,您可以在unicode函數中注意調用外鍵unicode函數。這些導致進一步的子查詢。 – 2012-03-19 16:38:12

3

這讓我瘋狂。 list_select_related設置爲True,但是在list_display中向用戶添加外鍵會在admin中爲每行生成一個查詢,這會使列表變慢。 Select_related是True,所以Django管理員不應該在每一行調用這個查詢。 發生了什麼事?

+0

史蒂夫K你有沒有得到這個固定的?我完全相同,並且瘋了...... – 2013-12-20 17:55:43

+1

是的,我在2年前就修好了。您的'ModelAdmin'需要重寫'get_queryset'(參見文檔)以添加'select_related()'語句。你也可以使用'only'和'defer'字段,任何你想要的。 – 2013-12-23 01:44:08

+0

Thankyou @ steve-k感謝你我可能會花一些時間與我的家人在這個聖誕節。 – 2013-12-23 15:16:35

0

這是Django管理員和外鍵的一個很老的問題。這裏發生的是,當你嘗試加載一個對象時,它會試圖獲取該外鍵的所有對象。所以我們可以說你正在試圖加載一些球隊的球員(比如說球隊的數量約爲100),它會一直保持包括所有的100支球隊。您可以嘗試使用稱爲raw_fields的東西來優化它們。這樣做不是必須一次調用所有內容,而是要限制調用的次數,並確保只有在事件觸發時(即選擇團隊時)才能進行調用。 如果這看起來有點像一個UI一塌糊塗,你可以嘗試使用這個類:

""" 
For Raw_id_field to optimize django performance for many to many fields 
""" 
class RawIdWidget(ManyToManyRawIdWidget): 
    def label_for_value(self, value): 
     values = value.split(',') 
     str_values = [] 
     key = self.rel.get_related_field().name 
     for v in values: 
      try: 
       obj = self.rel.to._default_manager.using(self.db).get(**{key: v}) 
       x = smart_unicode(obj) 
       change_url = reverse(
        "admin:%s_%s_change" % (obj._meta.app_label, obj._meta.object_name.lower()), 
        args=(obj.pk,) 
       ) 
       str_values += ['<strong><a href="%s">%s</a></strong>' % (change_url, escape(x))] 
      except self.rel.to.DoesNotExist: 
       str_values += [u'No input or index in the db'] 
     return u', '.join(str_values) 

class ImproveRawId(admin.ModelAdmin): 
    raw_id_fields = ('created_by', 'updated_by') 
    def formfield_for_dbfield(self, db_field, **kwargs): 
     if db_field.name in self.raw_id_fields: 
      kwargs.pop("request", None) 
      type = db_field.rel.__class__.__name__ 
      kwargs['widget'] = RawIdWidget(db_field.rel, site) 
      return db_field.formfield(**kwargs) 
     return super(ImproveRawId, self).formfield_for_dbfield(db_field, **kwargs) 

只要確保你正確地繼承類。我猜想像TeamFixture_ModelAdmin (ImproveRawIdFieldsForm)。這很可能會在你的django管理中給你一個非常酷的性能提升。