我有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'
我可以“轻松”避免两次查询数据库,而我只能在这种情况下查询一次吗?
答案 0 :(得分:1)
您可以向选择框提供值列表,而不是向您的字段提供查询集。
suitable_sponsors = Sponsor.objects.suitable_for_quote_request(quote_request)\
.values_list('id', 'sponsor_name')
if 'sponsors' not in initial:
initial['sponsors'] = [s.id for s in suitable_sponsors[:3]]
self.fields['sponsors'].choices = suitable_sponsors
您可能需要将ModelMultipleChoiceField更改为MultipleChoiceField。