我有一个 django 模型形式“Recipe”,其中有一个指向模型“Ingredient”的外键字段。
呈现表单时,我得到一个 SELECT 列表,其中的 ID 与成分 ID 匹配,文本显示等于字段的字符串表示形式。
但是,我想向选择列表添加一个数据属性,以匹配成分查询集中呈现的选项。
例如,假设这是当前正在渲染的内容:
<option value="1158">Carrots</option>
<option value="1159">Strawberry</option>
<option value="1160">Onion</option>
<option value="1161">Spinach</option>
但是我想为相关对象添加一个数据属性:
<option value="1158" data-ingredient-type="vegetable">Carrots</option>
<option value="1159" data-ingredient-type="fruit">Strawberry</option>
<option value="1160" data-ingredient-type="vegetable">Onion</option>
<option value="1161" data-ingredient-type="vegetable">Spinach</option>
请您参考如下方法:
一种方法是使用自定义 Select 小部件,它允许通过小部件选择的 label 部分在选项中传递单个属性: (code from this great answer)
class SelectWithOptionAttribute(Select):
"""
Use a dict instead of a string for its label. The 'label' key is expected
for the actual label, any other keys will be used as HTML attributes on
the option.
"""
def create_option(self, name, value, label, selected, index,
subindex=None, attrs=None):
# This allows using strings labels as usual
if isinstance(label, dict):
opt_attrs = label.copy()
label = opt_attrs.pop('label')
else:
opt_attrs = {}
option_dict = super().create_option(name, value,
label, selected, index, subindex=subindex, attrs=attrs)
for key,val in opt_attrs.items():
option_dict['attrs'][key] = val
return option_dict
要填充单个选项,请覆盖 ModelChoiceField 子类上的 label_from_instance 方法 (see django docs) :
IngredientChoiceField(ModelChoiceField):
"""ChoiceField with puts ingredient-type on <options>"""
# Use our custom widget:
widget = SelectWithOptionAttribute
def label_from_instance(self, obj):
# 'obj' will be an Ingredient
return {
# the usual label:
'label': super().label_from_instance(obj),
# the new data attribute:
'data-ingredient-type': obj.type
}
最后,简单的在表单中使用这个字段:
RecipeModelForm(ModelForm):
class Meta:
model = Recipe
fields = [
# other fields ...
'ingredients',
]
field_classes = {
'ingredients': IngredientChoiceField
}
