【发布时间】: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