【问题标题】:'with' tag problems in djangodjango中的'with'标签问题
【发布时间】:2012-03-14 18:05:27
【问题描述】:

我有一个带有方法的模型“发票”

def item_objects(self):
    return self.invoiceitem_set.filter(kind='item')

然后我在其上下文“发票”中有一个包含该模型的模板

在该模板中,我使用 with 标签来尝试缓存 item_objects

{% with item_object=invoice.item_objects%}
    {{item_object}}
    {{item_object}}
{% endwith %}

尽管我每次调用 {{item_object}} 时仍然会访问数据库

我做错了什么?

【问题讨论】:

    标签: django templates tags


    【解决方案1】:

    您的简化代码可能隐藏了问题,因为您描述的行为不应该发生。 with 模板标签的全部目的是缓存昂贵方法的结果以供以后使用。

    但是,您的方法item_objects 返回一个QuerySet,当您将它分配给item_object 时,它仍然是一个QuerySetQuerySets 是延迟加载的,所以到目前为止,还没有数据库命中。因此,根据您对item_object 的实际操作,您可能会对查询性能产生负面影响。

    例如,即使您正在处理缓存的QuerySet,以下内容也会导致对数据库的两次查询:

    {{ item_object.count }}
    {{ item_object|first }}
    

    您需要注意对查询集执行的操作以及顺序。例如,如果您知道您将在某个时间点遍历查询集,但您需要先进行计数,那么使用{{ item_object|length }} 而不是{{ item_object.count }} 实际上更有效

    【讨论】:

    • 使用调试工具,我看到每个 {{item_object}} 我点击了数据库。我不是在看计数或其他任何东西。 {{item_object}} 这里是模板pastebin.com/PJQFYYE6
    • 引用查询集本身会调用__repr__。 Django 可能每次都强制执行一个新查询,因为表示取决于实时结果。但是,这并不是您在模板中故意做的事情(即您将循环遍历查询集或对其执行某种其他操作,例如计数)。如果您真的在现实世界中做某事,您应该不会再看到对 DB 的多次点击。
    • 克里斯是对的。我建议查看 James Bennett 最近在 Pycon 上的 Django In Depth 会议,其中他解释了触发 QuerySet 评估的原因。另外:将invoice.item_objects 更改为ìnvoice.item_objects.all 只会评估一次查询集。
    猜你喜欢
    • 2011-10-28
    • 2016-06-02
    • 2012-07-05
    • 2010-11-23
    • 1970-01-01
    • 2020-01-24
    • 2011-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多