3

我有一个定义如下的待办事项模型:

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")

我想列出所有不完整的操作:

actions = Action.objects.filter(complete=False)

我的动作列表模板循环:

{% 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 %} 上访问数据库。

有没有更好的方法来编写我的查询,以便不会在循环的每次迭代中对数据库进行 ping 操作?我认为它与 select_related 有关,但我不确定如何处理django-taggit

更新我得到了部分答案。select_related 确实有效,但我必须指定重复出现,可能是因为我不能将它用于标签:

actions = Action.objects.select_related('reoccurance').filter(complete=False)

问题仍然存在,我为模板循环中的每个“action.tags.all”都打了数据库。是否可以在 django-taggit 上使用某种预取?

4

2 回答 2

1

可以prefetch_related用来检索标签,但您需要避开“标签”属性,因为 - 正如 jdi 所说 - 这是一个自定义管理器而不是真正的关系。相反,您可以这样做:

actions = Action.objects.select_related('reoccurance').filter(complete=False)\ .prefetch_related('tagged_items__tag')

不幸的是,action.tags.all在您的模板代码中不会使用预取,并且最终会执行自己的查询 - 因此您也需要采取相当棘手的步骤来绕过“标签”管理器:

{% for tagged_item in action.tagged_items.all %}
    <span>{{ tagged_item.tag }}</span>{% if not forloop.last %}, {% endif %}
{% endfor %}

(Ed.:如果你得到“'QuerySet' 对象没有属性'prefetch_related'”,这表明你使用的 Django 版本低于 1.4,prefetch_related 不可用。)

于 2013-10-03T17:40:34.043 回答
-1

问题在于它tags不是一个字段,而是一个自定义管理器,它位于类级别并且只是进行查询。

我不确定这是否适用于自定义管理器,因为它适用于产生类似查询集的多对多字段等。但是如果你使用的是 django 1.4,你可以试试prefetch_related. 它将再做一个查询,批量处理关系并缓存它们。

再次免责声明:我不知道这是否适用于经理

actions = Action.objects.select_related('reoccurance').filter(complete=False)\
                .prefetch_related('tags')
于 2012-08-31T01:57:20.803 回答