【发布时间】:2016-07-11 23:34:48
【问题描述】:
我有一个Form 和一个ModelMultipleChoiceField 哪个queryset is generated at Form instanciation。我还希望最初检查三个首选选项。这是我的代码:
class DeliveryForm(forms.Form):
content = forms.CharField(
label=_("Contenu"), validators=[
MinLengthValidator(20),
MaxLengthValidator(5000),
], widget=Wysiwyg)
sponsors = DeliverySponsorsField(
label=_("Commanditaires"), validators=[
MaxLengthValidator(3),
], error_messages={
'max_length': _(
"Vous ne pouvez pas sélectionner plus de 3 commanditaires."),
}, queryset=None)
def __init__(self, *args, **kwargs):
quote_request = kwargs.pop('quote_request')
suitable_sponsors = Sponsor.objects.all().suitable_for_quote_request(
quote_request)
initial = kwargs.pop('initial', None) or {}
if 'content' not in initial:
initial['content'] = quote_request.description
if 'sponsors' not in initial:
initial['sponsors'] = suitable_sponsors[:3]
kwargs['initial'] = initial
super().__init__(*args, **kwargs)
self.fields['sponsors'].queryset = suitable_sponsors
DeliverySponsorsField 是ModelMultipleChoiceField 的子类,它使我能够显示复杂的小部件:
class DeliverySponsorsRenderer(CheckboxFieldRenderer):
outer_html = '<ul{id_attr} class="media-list">{content}</ul>'
inner_html = '<li class="media">[...]</li>'
def render(self):
id_ = self.attrs.get('id')
output = []
for i, choice in enumerate(self.choices):
choice_value, sponsor = choice
widget = self.choice_input_class(self.name, self.value,
self.attrs.copy(), choice, i)
output.append({
'x': sponsor.x, 'y': sponsor.y, 'z': sponsor.z, ...})
content = format_html_join('\n', self.inner_html, output)
# I have my own `format_html_join` function that handles keyword arguments
return format_html(self.outer_html,
id_attr=format_html(' id="{}"', id_) if id_ else '',
content=content)
class DeliverySponsorsWidget(CheckboxSelectMultiple):
renderer = DeliverySponsorsRenderer
class DeliverySponsorsField(ModelMultipleChoiceField):
widget = DeliverySponsorsWidget
def label_from_instance(self, obj):
return obj
这就像一个魅力。
嗯,不完全是因为以下几行计算查询集:
initial['sponsors'] = suitable_sponsors[:3]
并且查询集也会在之后进行评估以生成可能的选择。虽然只有一个查询就足够了(因为suitable_sponsors[:3] 是suitable_sponsors 的子集。
我试图强制查询集评估:
# Replaced
suitable_sponsors = Sponsor.objects.all().suitable_for_quote_request(
quote_request)
# with
suitable_sponsors = list(
Sponsor.objects.all().suitable_for_quote_request(quote_request))
但是,ModelMultipleChoiceField 抱怨 queryset 不是 QuerySet。更准确地说,它抱怨 queryset.all 未定义:
File "/home/antoine/.venvs/aladom_v6/lib/python3.4/site-packages/django/forms/widgets.py" in get_renderer
763. choices = list(chain(self.choices, choices))
File "/home/antoine/.venvs/aladom_v6/lib/python3.4/site-packages/django/forms/models.py" in __iter__
1105. queryset = self.queryset.all()
Exception Type: AttributeError at /admin/quotation/requalification/141369/deliver/
Exception Value: 'list' object has no attribute 'all'
我可以“轻松”避免两次查询数据库,而我只能查询一次这种情况吗?
【问题讨论】:
-
除非额外的查询导致性能问题,否则这可能是过早优化的情况。
-
@Alasdair 当然,这就是我要求“简单”解决方案的原因。关键不是要创建一个自负的机制来避免这种额外的查询。如果我可以轻松避免它,那很好。如果这需要一些异国情调的工作,我宁愿保留额外的查询。
-
@Antoine:“一英寸,一英里”,你必须对表现保持警惕:) 然后有时你必须让步
-
没问题,我的问题主要是出于好奇。我知道我有更重要的事情要关心。 :)
标签: django django-forms django-queryset