You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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:使用外部模板文件

  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 %}
  1. 自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 08:42:39