2012-08-30 117 views
3

我在下面定义的待办事项模式:优化Django的查询拉外键和Django的taggit关系

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 action in action.tags.all%}中。

有没有更好的方式来编写我的查询,以便数据库不会针对循环的每次迭代进行ping?我认为它与select_related有关,但我不知道该怎么做django-taggit

更新我得到了我的答案的一部分。 select_related的工作,但我必须指定reoccurance,可能是因为我不能用它来标记:

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

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

回答

-1

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

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

免责声明又说:我不知道这是否适用于管理者

actions = Action.objects.select_related('reoccurance').filter(complete=False)\ 
       .prefetch_related('tags') 
+0

感谢您的输入。免责声明可能是正确的:'QuerySet'对象没有'prefetch_related'属性。我是否应该接受,我将有一个数据库,以便在行动中采取行动? –

+0

我不能100%确定,因为我从来没有看过那个应用程序,但我的直觉告诉我,这只能在字段上完成。现在,您可能可以在一个查询中手动查询所有标记,并使用该结果代替循环中每个对象的thr管理器。 – jdi

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 %} 

(编辑:如果您收到“‘查询集’对象有没有属性‘prefetch_related’”,这表明你在低于1.4版本的Django的,其中prefetch_related不可用。)