【问题标题】:Django inline formsets and choicefields generate too many db queriesDjango 内联表单集和选择字段生成太多数据库查询
【发布时间】:2012-03-23 21:29:57
【问题描述】:

我有一个带有许多外键字段的模型,例如具有“类型”、“级别”、“颜色”、“强度”字段的模型产品(只是一个通用示例)。

然后我有一个页面可以使用 Type 表单编辑给定类型的所有产品,其中产品作为内联表单集,并可选择使用 extra=10 内联添加其他产品。

我觉得很奇怪的是,每次我在模板上输出一个外键选择字段时,Django 都会查询数据库以获取选项(每次)。

例如:

{% for form in formset %}
    {{ form.level }}
    {{ form.color }}
    {{ form.intensity }}
{% endfor %}

对于 20 个产品(和 10 个空的额外表单),上面的代码从级别、颜色和强度发出 30 个select * from ...,总共 90 个查询(使用 Django 调试工具栏显示),其中 3 个应该足够了。这些选项不太可能在请求中更改,但即使他们这样做了,我也绝对不希望某些新添加的选项仅出现在最后 5 个表单中。

有什么方法可以优化我的模型/表单/视图/模板,这样数据库就不会像这样不必要地受到冲击?

-

免责声明:我对 django 和 python 还比较陌生,不禁想到一定有办法以某种方式解决这个问题。

【问题讨论】:

    标签: python django inline-formset


    【解决方案1】:
    field_queryset = Test.objects.all()    
    for form in formset:
            form.fields['test_field'].queryset = field_queryset
    

    像这样。

    【讨论】:

    • 不错的丹尼斯,有道理,只是让他们都使用相同的查询集对象。你花了 11 个月的时间才给出答案,而我又花了 8 个月的时间来接受它。同时,通过完全缓存 'type'、'level'、'color' 类型来解决这个问题,前提是这些类型几乎是不会改变的常量。但是谢谢,这是一个简单的方法,我下次会记住。
    • 这不起作用。在您可以像这样替换它们之前,表单将使用默认查询集构建,因此它会执行尽可能多的查询。
    • @Adrián,我认为实际上是“是和不是”。你是对的,默认查询集可能会在 Form 构造函数中创建。但是,创建查询集与查询数据库不同。如果在发出第一个查询之前替换查询集,您仍然可以保存对数据库的所有不必要的调用。在模板中显示第一个表单之前,以及在每个表单上调用 save 之前,您需要替换它们。
    • 是的,这是有道理的,但不是 :( 显然,(正如我在 IRC 上被告知的那样),ModelChoiceField 克隆了查询集,因此需要一个自定义表单字段。
    • 这不起作用。这些表单似乎在查询集上调用了 .all() ,它创建了一个新的查询集,它不与原始查询集和其他表单共享结果。 (Django 1.7.1)
    【解决方案2】:

    您可以change the queryset used by the formset,然后您可以使用select_related() 来生成FK 连接,而不是在每次forloop 迭代时执行查询。

    【讨论】:

    • 我看不出这些在这种情况下会有什么帮助。查询集用于选择产品的当前值,而 select_related 可以帮助获取当前链接到每个产品的级别/颜色/强度对象。 select_related 如何实际帮助预取整组选择选项以填充选择框?
    • 好的,你可以使用 ajax 自动完成 (django-ajax-selects) 或者使用查询缓存 (johnnycache)。
    • 这帮助我减少了表单集中的查询数量。
    猜你喜欢
    • 1970-01-01
    • 2011-07-13
    • 2018-06-02
    • 1970-01-01
    • 1970-01-01
    • 2013-10-23
    • 1970-01-01
    • 2013-11-20
    • 2018-11-07
    相关资源
    最近更新 更多