[英]Optimize django query to pull foreign key and django-taggit relationship
I have a todo model defined below: 我有一个todo模型定义如下:
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 %}
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 %}. 使用django-debug-toolbar ,我看到对于每个动作,我都在{%if action.reoccurance%}和{%for action in action.tags.all%}中访问数据库。
Is there a better way to write my query so that the database isn't pinged for every iteration of the loop? 有没有更好的方法来编写我的查询,以便数据库不会针对循环的每次迭代进行ping操作? I think it has something to do with select_related, but I'm not sure what to do about django-taggit .
我认为它与select_related有关,但我不知道如何处理django-taggit 。
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:
select_related确实有效,但我必须指定reoccurance,可能是因为我不能将它用于标签:
actions = Action.objects.select_related('reoccurance').filter(complete=False)
The problem still remains that I hit the database for every "action.tags.all" in the template loop. 问题仍然存在,我在模板循环中为每个“action.tags.all”命中数据库。 Is it possible to use some sort of prefetch on django-taggit?
是否可以在django-taggit上使用某种预取?
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. 可以使用
prefetch_related
来检索标签,但是你需要绕过'tags'属性,因为 - 正如jdi所说 - 这是一个自定义管理器而不是真正的关系。 Instead, you can do: 相反,你可以这样做:
actions = Action.objects.select_related('reoccurance').filter(complete=False)\\ .prefetch_related('tagged_items__tag')
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: 不幸的是,你的模板代码中的
action.tags.all
将不会使用预取,并最终会自己进行查询 - 所以你需要采取相当狡猾的步骤绕过'标签'管理器:
{% for tagged_item in action.tagged_items.all %}
<span>{{ tagged_item.tag }}</span>{% if not forloop.last %}, {% endif %}
{% endfor %}
(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.) (编辑:如果你得到''QuerySet'对象没有属性'prefetch_related'“,那表明你的版本是低于1.4的Django,其中prefetch_related不可用。)
The problem is that tags
is not a field, but a custom manager, which lives at the class-level and simply does queries. 问题是
tags
不是一个字段,而是一个自定义管理器,它位于类级别,只是执行查询。
I am not sure if this will work on custom managers, as it is meant for many-to-many fields and the like that produce similar query sets. 我不确定这是否适用于自定义管理器,因为它适用于生成类似查询集的多对多字段等。 But if you are using django 1.4 you can try the
prefetch_related
. 但是如果您使用的是django 1.4,则可以尝试使用
prefetch_related
。 It will do one more query that batches out the relations and caches them. 它将再做一个查询,批处理关系并缓存它们。
Disclaimer again: I don't know if this works for managers 免责声明:我不知道这对管理者是否有效
actions = Action.objects.select_related('reoccurance').filter(complete=False)\
.prefetch_related('tags')
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.