优化django查询拉外键和django-taggit关系
我有一个如下定义的待办事项模型:
I have a todo model defined below:
class Action(models.Model):
name = models.CharField("Action Name", max_length=200, unique = True)
complete = models.BooleanField(default=False, verbose_name="Complete?")
reoccurance = models.ForeignKey(Reoccurance, blank=True, null=True, verbose_name="Reoccurance")
notes = models.TextField("Notes", blank=True)
tags = TaggableManager()
class Reoccurance(models.Model):
label = models.CharField("Label", max_length=50, unique = True)
days = models.IntegerField("Days")
我想列出所有未完成的操作:
I want to list all of the actions that are incomplete:
actions = Action.objects.filter(complete=False)
我的动作列表模板循环:
My template loops of the actions list:
{% for action in actions %}
<p>{{ action }}</p>
{% if action.reoccurance %}
<p>{{ action.reoccurance }}</p>
{% endif %}
{% for tag in action.tags.all %}
<span>{{ tag }}</span>{% if not forloop.last %}, {% endif %}
{% endfor %}
{% endfor %}
使用 django-debug-toolbar,我看到每个动作,我在 {% if action.reoccurance %} 和 {% for tag in action.tags.all %} 上访问数据库.
Using django-debug-toolbar, I see that for every action, I'm hitting the database on {% if action.reoccurance %} and {% for tag in action.tags.all %}.
是否有更好的方法来编写我的查询,以便在每次循环迭代时都不会 ping 数据库?我认为它与 select_related 有关,但我不确定如何处理 django-taggit一>.
Is there a better way to write my query so that the database isn't pinged for every iteration of the loop? I think it has something to do with select_related, but I'm not sure what to do about django-taggit.
更新 我得到了部分答案.select_related 确实有效,但我必须指定 reoccurance,可能是因为我不能将它用于标签:
Update I got part of my answer. select_related does work, but I had to specify reoccurance, probably because I can't use it for tags:
actions = Action.objects.select_related('reoccurance').filter(complete=False)
问题仍然存在,我为模板循环中的每个action.tags.all"点击了数据库.是否可以在 django-taggit 上使用某种预取?
The problem still remains that I hit the database for every "action.tags.all" in the template loop. Is it possible to use some sort of prefetch on django-taggit?
推荐答案
可以使用 prefetch_related
来检索标签,但您需要避开 'tags' 属性,因为 - 作为 jdi说 - 这是一个自定义管理器,而不是一个真正的关系.相反,您可以这样做:
It's possible to use prefetch_related
to retrieve the tags, but you need to sidestep around the 'tags' property, since - as jdi says - this is a custom manager rather than a true relation. Instead, you can do:
actions = Action.objects.select_related('reoccurance').filter(complete=False).prefetch_related('tagged_items__tag')
不幸的是,您的模板代码中的 action.tags.all
不会使用预取,最终会执行自己的查询 - 因此您需要采取相当笨拙的步骤绕过标签"经理也在那里:
Unfortunately, action.tags.all
in your template code will not make use of the prefetch, and will end up doing its own query - so you need to take the rather hacky step of bypassing the 'tags' manager there too:
{% for tagged_item in action.tagged_items.all %}
<span>{{ tagged_item.tag }}</span>{% if not forloop.last %}, {% endif %}
{% endfor %}
(编者:如果您得到'QuerySet' 对象没有属性 'prefetch_related'",则表明您使用的是低于 1.4 的 Django 版本,其中 prefetch_related 不可用.)
(Ed.: if you're getting "'QuerySet' object has no attribute 'prefetch_related'", that suggests that you're on a version of Django below 1.4, where prefetch_related isn't available.)
相关文章