Form
はModelMultipleChoiceField
です。queryset is generated at Form instanciationです。私はまた、3つの最初の選択肢を最初にチェックしたい。ここに私のコードは次のとおりです。Prefilled 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
これは魔法のように動作:
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
のサブクラスです。
まあ、正確に次の行は、クエリセット評価されるためではない:
initial['sponsors'] = suitable_sponsors[:3]
をそしてクエリセットも可能な選択肢を生成するために、後で評価されます。 。
# 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
をされていない文句より正確には、:suitable_sponsors[:3]
はsuitable_sponsors
のサブセットであるため、唯一のクエリは(十分であろうけれども
私はクエリセットの評価を強制しようとしました。それはおよそ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'
私はONLそれを問い合わせることができながら、私は「簡単に」二度データベースを照会避けることができますこの場合は一度ですか?
余分なクエリでパフォーマンスの問題が発生していない限り、これは時期尚早の最適化のケースかもしれません。 – Alasdair
@Alasdair確かに、私は「シンプルな」ソリューションを求めています。重要なのは、この余分なクエリを避けるために、誇張された機械を作成しないことです。私が簡単にそれを避けることができれば、良い。これはいくつかのエキゾチックな仕事が必要な場合は、私はむしろ余分なクエリを保つだろう。 –
@Antoine: "1インチを出して1マイルくらい"、パフォーマンスに注意を払わなければなりません:)もう一度、いつかあなたに与えなければなりません –