我正在努力改进我的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次查询。
我意识到这听起来像是一个陈述而不是一个问题,所以请尽可能证明我错了
答案 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