2014-01-17 60 views
0

我有一個跟蹤出版物的Django應用程序。出版物與作者有着M2M的關係。使用MySQL。Django:減少ListView模板上的查詢

簡單。

class Publication(models.Model): 

    slug = models.SlugField(unique=True, max_length=128) 
    author = models.ManyToManyField(Author, blank=True, null=True, through='Authorship') 
    title = models.CharField(max_length=128) 

    def __unicode__(self): 
     return unicode(self.title) 

我有一個ListView向他們展示:

class PubList(ListView): 
    model = Publication 

大部分是研究論文,有幾個作家。在我的模板上,我想顯示一個作者列表。所以我做了這樣的事情:

{% for obj in publication_list %} 
    <tr> 
     <td><a href="{{ obj.get_absolute_url }}">{{ obj.title }}</a></td> 
     <td> 
      {% for a in obj.authorship_set.all %} 
       {{ a.author.last_name }}, {{ a.author.first_name }} 
       {% if not forloop.last %}; {% endif %} 
      {% endfor %} 
     </td>  
    </tr>  
{% endfor %} 

那麼,你可能會猜測我的問題是什麼。隨着Publications的數量增加,數據庫調用起飛。有超過500個查詢需要119份出版物

我解決了它,像這樣: 在我PubList(ListView)我重寫get_context_data這個函數的輸出設置爲背景[「作家」]:

def get_authors_by_pub(): 

    from django.db import connection 
    sql = """SELECT p.id, 
       (
        SELECT GROUP_CONCAT(CONCAT(a.last_name, ', ', a.first_name) SEPARATOR '; ') 
        FROM publication_authorship ap 
        LEFT JOIN publication_author a ON a.id = ap.author_id 
        WHERE ap.publication_id = p.id 
       ) 
      FROM publication_publication p""" 

    cursor = connection.cursor() 
    cursor.execute(sql) 
    rows = cursor.fetchall() or() 
    authors = {} 
    for r in rows: 
     if r[1]: 
      authors[r[0]] = r[1] 

    return authors 

現在我有一個作家詞典,如: {1: 'Tesla, Nikola; Clarke, Aurthur; Hooper, Grace', 2: 'Hopper, Grace; Simpson, Marge'}

然後,在模板,因爲我不能鍵訪問的字典,我遍歷authors找到有鑰匙的那些是publication.id

<td> 
    {% for key, value in authors.items %} 
     {% if key == obj.id %} 
      {{ value }} 
     {% endif %} 
    {% endfor %} 
</td> 

This Works,just 2 queries。即使作者查詢是殘酷的,嵌套的SELECTs,它的速度比以前快了幾個數量級。

但我想知道是否有更好的方法。對於模板上的每個出版物,我都覺得有點棘手。我希望能夠在模板上使用authors[obj.id]

您認爲如何?

回答

1

Django的覆蓋相關查詢和延遲加載相當廣泛,在它的文檔......當Django提供你爲什麼會編寫了這一切:

Publication.objects.prefetch_related('authors').all() 

https://docs.djangoproject.com/en/1.6/topics/db/queries/#related-objects https://docs.djangoproject.com/en/1.6/ref/models/querysets/#prefetch-related

您可以使用上面的查詢集在您的ListView中:

class PublList(ListView): 
    queryset = Publication.objects.prefetch_related('authors') 
+0

因爲我是啞巴?謝謝!! –

+1

沒有人是個笨拙的伴侶,我們都在學習:)只需要更多的文檔閱讀;) – petkostas

+2

您可以將'.all()'截斷 - 不是必需的。 – meshy