Skip to main content
 首页 » 编程设计

python之如何将数据属性添加到 django modelform modelchoicefield

2024年10月17日27三少

我有一个 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 
    }