如何让Django生成的单选按钮不被div包裹并自定义结构?
Django RadioSelect 自定义HTML结构方案
问题说明
使用如下Django表单代码生成单选按钮:
from django import forms class MCQCollectionForm(forms.Form): user_input = forms.ChoiceField( widget=forms.RadioSelect, label='', choices=enumerate(['option 1', 'option 2']) )
得到的HTML会被额外的div包裹,且选项文本未放入span标签:
<div id="id_user_input"> <div> <label for="id_user_input_0"><input id="id_user_input_0" name="user_input" required="" type="radio" value="0"> option 1</label> </div> <div> <label for="id_user_input_1"><input id="id_user_input_1" name="user_input" required="" type="radio" value="1"> option 2</label> </div> </div>
需要生成的目标结构:去掉多余div,给label添加user-item类,将选项文本放入span标签,同时保留id、required等属性:
<label class="user-item"> <input name="user_input" type="radio" ... > <span>Lorem ipsum dolor</span> </label> <label class="user-item"> <input name="user_input" type="radio" ... > <span>Lorem ipsum dolor</span> </label>
解决方案:自定义RadioSelect的渲染模板
Django支持通过自定义Widget的渲染模板来修改输出的HTML结构,无需JS或手动修改,有两种实现方式:
方式1:使用外部模板文件
- 在项目
templates目录下创建widgets/custom_radio.html模板文件,内容如下:
{% for widget in widget.subwidgets %} <label class="user-item" for="{{ widget.attrs.id }}"> {{ widget.tag }} <span>{{ widget.choice_label }}</span> </label> {% endfor %}
- 自定义RadioSelect子类并指定模板:
from django import forms class CustomRadioSelect(forms.RadioSelect): template_name = 'widgets/custom_radio.html' class MCQCollectionForm(forms.Form): user_input = forms.ChoiceField( widget=CustomRadioSelect, label='', choices=enumerate(['option 1', 'option 2']) )
方式2:内联模板字符串(无需额外文件)
如果不想创建单独的模板文件,可以直接在Widget类中定义模板内容:
from django import forms from django.forms.renderers import get_default_renderer class CustomRadioSelect(forms.RadioSelect): def render(self, name, value, attrs=None, renderer=None): renderer = renderer or get_default_renderer() template = """ {% for widget in widget.subwidgets %} <label class="user-item" for="{{ widget.attrs.id }}"> {{ widget.tag }} <span>{{ widget.choice_label }}</span> </label> {% endfor %} """ context = self.get_context(name, value, attrs) return renderer.render(template, context) class MCQCollectionForm(forms.Form): user_input = forms.ChoiceField( widget=CustomRadioSelect, label='', choices=enumerate(['option 1', 'option 2']) )
两种方式都会输出符合要求的HTML结构,自动保留radio输入框的id、required等属性,同时去掉多余的div包裹,给label添加指定类名,选项文本也会被span标签包裹。
内容的提问来源于stack exchange,提问作者nlblack323
相关产品推荐
相关产品推荐

