The cause: iterating over an unordered collection (原因:遍历无序集合)
crispy_forms
's FormHelper.render_layout
does this: (crispy_forms
的FormHelper.render_layout
为此:)
fields = set(form.fields.keys())
left_fields_to_render = fields - form.rendered_fields
for field in left_fields_to_render:
...
At this point, left_fields_to_render
is a set
: {'text', 'no_bots'}
(此时, left_fields_to_render
是一个set
: {'text', 'no_bots'}
)
A set
is an unordered collection. (set
是无序集合。)
This sometimes returns False
: [a for a in {'text', 'no_bots'}] == ['text', 'no_bots']
(有时会返回False
: [a for a in {'text', 'no_bots'}] == ['text', 'no_bots']
)
You can try this by opening several different instances of the Python interpreter — I noticed that it's usually consistent within an instance of a Python interpreter. (您可以通过打开几个不同的Python解释器实例来尝试这一操作-我注意到它通常在Python解释器实例中是一致的。)
The fix: iterate over a list (解决方法:遍历列表)
Basically: (基本上:)
fields = tuple(form.fields.keys())
left_fields_to_render = list_difference(fields, form.rendered_fields)
for field in left_fields_to_render:
...
I have submitted a PR for a more complete fix at django-crispy-forms/django-crispy-forms#952 . (我已经提交了django-crispy-forms / django-crispy-forms#952的PR,以获取更完整的修复程序。)
The workaround: explicitly specify the fields in the layout (解决方法:在布局中显式指定字段)
Arguably, the intended usage of layout if you don't set render_unmentioned_fields = True
. (如果没有设置render_unmentioned_fields = True
,则可以说是布局的预期用途。)
You already call self.helper.add_layout
for two of the four fields; (您已经为四个字段中的两个调用了self.helper.add_layout
;) you can just go all the way: (您可以一路走下去:)
self.helper.add_layout(MultiWidgetField(
Row(
Div('sender_name', css_class='col-md-6'),
Div('sender_email', css_class='col-md-6'),
),
'text',
'no_bots',
))
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…