Django:减少ListView模板上的查询

时间:2014-01-17 20:51:40

标签: django django-templates django-class-based-views

我有一个跟踪出版物的Django应用程序。出版物与作者有M2M关系。使用MySQL。

简单。

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的数量增加,数据库调用量猛增。 119种出版物有500多种查询。

我这样解决了: 在我的PubList(ListView)中,我覆盖get_context_data并将此函数的输出设置为上下文['authors']:

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> 

这个工作,只有2个查询。即使作者查询是残酷的,使用嵌套的SELECT,它也比以前快了几个数量级。

但我想知道是否有更好的方法。对于模板上的每个出版物,我觉得有点狡猾地遍历整个dict。我希望能够在模板上authors[obj.id]

您怎么看?

1 个答案:

答案 0 :(得分: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')