【问题标题】:Django: Reducing Queries on ListView TemplateDjango:减少对 ListView 模板的查询
【发布时间】:2014-02-07 08:35:31
【问题描述】:

我有一个跟踪出版物的 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]

你怎么看?

【问题讨论】:

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


    【解决方案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')
    

    【讨论】:

    • 因为我是个笨蛋?谢谢!!
    • 没有人是个笨蛋,我们都在学习 :) 只需要多阅读一下文档 ;)
    • 你可以把.all() 去掉——这不是必须的。
    猜你喜欢
    • 2020-06-02
    • 2010-12-14
    • 2014-07-31
    • 1970-01-01
    • 2016-07-10
    • 1970-01-01
    • 2020-03-25
    • 2011-09-24
    • 2018-01-08
    相关资源
    最近更新 更多