简体   繁体   English

优化django查询以获取外键和django-taggit关系

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM