django在已清理的数据上形成预取

时间:2015-12-18 11:08:18

标签: python django forms

我正在努力改进我的Django应用程序所做的数据库命中量,而且我的一个抱怨是使用Django表单。

当我使用表单获取页面时,它将从数据库加载对象以填充ModelChoiceField,这很棒。

当我发布一些表单数据时,表单将清理数据。现在,在表单的clean_foo方法中,我想访问其中一个foo对象关系:foo.bar。这将命中数据库以获取bar对象。

我有什么方法可以预取bar吗?我的意思是,当表单使用pk查找foo对象时,我是否可以预取bar?我可以在哪里做到这一点?

查看Django source code,似乎所选对象是使用.get()直接提取的,而不是.filter()

的查询集
def to_python(self, value):
    if value in self.empty_values:
        return None
    try:
        key = self.to_field_name or 'pk'
        value = self.queryset.get(**{key: value})    # <-- Right here
    except (ValueError, TypeError, self.queryset.model.DoesNotExist):
        raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice')
    return value

所以,那告诉我的是我不应该在那里尝试任何东西。我能做的最好的事情是

def clean_foo(self):
    foo = Foo.objects.filter(pk=self.cleaned_data['foo'].pk).select_related('bar')
    [...]

在那里,我可以预取其他逻辑所需的内容。所以它不会成为1个查询,但我最多可以进行2次查询。

我意识到这听起来像是一个陈述而不是一个问题,所以请尽可能证明我错了

2 个答案:

答案 0 :(得分:5)

您好像可以直接在您的字段的查询集定义中使用Expander

<Grid Background="LightGray">

    <Expander IsExpanded="True">
         <Expander.Header>
              <Grid Width="100" Height="50">
                   <Rectangle Fill="Red"></Rectangle>
              </Grid>
         </Expander.Header>

         <Rectangle Fill="Red"></Rectangle>

    </Expander>

</Grid>

答案 1 :(得分:2)

编辑:这是一个过于复杂的想法,传递一个合适的查询集,因为Daniel建议更简单。

您可以继承ModelChoiceField并覆盖to_python,使其select_related

除非您的表单中有许多外键,或者页面,字段上有许多表单,否则保存一个查询可能不值得额外复杂。

示例可能看起来像

class MyModelChoiceField(forms.ModelChoiceField):
    def __init__(self, *args, select_related=(), prefetch_related=(), **kwargs):
        super(MyModelChoiceField, self).__init__(*args, **kwargs):
        self._selects = select_related
        self._prefetches = prefetch_related

    def to_python(self, value):
        if value in self.empty_values:
            return None
        try:
            key = self.to_field_name or 'pk'
            values = self.queryset.filter(
                **{key: value}
            ).select_related(
                *self._selects
            ).prefetch_related(
                *self._prefetches
            )
            value = values.first()
        except (ValueError, TypeError, self.queryset.model.DoesNotExist):
            raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice')
        return value