如何让Django表单显示html必需属性?

时间:2011-09-26 23:36:37

标签: html django forms html5

我有这个表单字段:

email = forms.EmailField(
  required=True,
  max_length=100,
)

它具有必需属性,但在html中没有添加html属性required。事实上它甚至没有使用email作为字段类型,它使用text ...虽然看起来好像是max_length。

实际值:

<input id="id_email" type="text" name="email" maxlength="100">

预期:

<input id="id_email" type="email" name="email" maxlength="100" required="true">

如何让Django在html表单中使用正确的属性?

6 个答案:

答案 0 :(得分:16)

Django表单元素是针对<input />编写的,因为它存在于HTML 4中,其中type="text"是电子邮件地址的正确选项。也没有required="true"

如果您想要自定义HTML属性,则需要小部件attrs关键字参数。它看起来像这样:

email = forms.EmailField(
    max_length=100,
    required=True,
    widget=forms.TextInput(attrs={ 'required': 'true' }),
)

您可以查看有关小部件here的更多文档。 attrs的讨论就在该页面的底部附近。

关于type="email",您可以将其发送到attrs字典,Django将智能地覆盖其默认值。如果这不是您得到的结果,那么您的路由是子类forms.TextInput,然后将其传递给widget关键字参数。

答案 1 :(得分:8)

结合Daniel和Daniel的答案,我通常将这个mixin用于我的表单:

from django.contrib.admin.widgets import AdminFileWidget
from django.forms.widgets import HiddenInput, FileInput


class HTML5RequiredMixin(object):

    def __init__(self, *args, **kwargs):
        super(HTML5RequiredMixin, self).__init__(*args, **kwargs)
        for field in self.fields:
            if (self.fields[field].required and
               type(self.fields[field].widget) not in
                    (AdminFileWidget, HiddenInput, FileInput) and 
               '__prefix__' not in self.fields[field].widget.attrs):

                    self.fields[field].widget.attrs['required'] = 'required'
                    if self.fields[field].label:
                        self.fields[field].label += ' *'

因此,当我必须创建一个新的表单或模型时,我只需使用:

class NewForm(HTML5RequiredMixin, forms.Form):
    ...

答案 2 :(得分:6)

Monkeypatching Widget是您最好的选择:

from django.forms.widgets import Widget
from django.contrib.admin.widgets import AdminFileWidget
from django.forms import HiddenInput, FileInput

old_build_attrs = Widget.build_attrs

def build_attrs(self, extra_attrs=None, **kwargs):
    attrs = old_build_attrs(self, extra_attrs, **kwargs)

    # if required, and it's not a file widget since those can have files
    # attached without seeming filled-in to the browser, and skip hidden "mock"
    # fileds created for StackedInline and TabbedInline admin stuff
    if (self.is_required
            and type(self) not in (AdminFileWidget, HiddenInput, FileInput)
            and "__prefix__" not in attrs.get("name", "")):
        attrs['required'] = 'required'

    return attrs

Widget.build_attrs = build_attrs

答案 3 :(得分:5)

还有使用过滤器的仅模板解决方案。我推荐django-widget-tweaks

{% load widget_tweaks %}

{{ form.email|attr:'required:true' }}

这很容易。

答案 4 :(得分:5)

自Django 1.10以来,这是内置的。

来自release notes

  

必填表单字段现在具有必需的HTML属性。将新的Form.use_required_attribute属性设置为False以禁用它。

答案 5 :(得分:4)

正如您所知,将字段必填属性设置为True仅适用于后端验证,如Django documentation中所述。

您真正想要的是向字段的Widget添加必需的属性:

email.widget.attrs["required"] = "required"

但是如果你真的想要编写优雅的DRY代码,你应该创建一个基础表单类,动态查找所有必需的字段并为你修改它们的widget必需属性(你可以根据需要命名,但是“BaseForm” “似乎很合适”:

from django.forms import ModelForm

class BaseForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(BaseForm, self).__init__(*args, **kwargs)
        for bound_field in self:
            if hasattr(bound_field, "field") and bound_field.field.required:
                bound_field.field.widget.attrs["required"] = "required"

然后让所有Form对象都从它下降:

class UserForm(BaseForm):
    class Meta:
        model = User
        fields = []

    first_name = forms.CharField(required=True)
    last_name = forms.CharField(required=True)
    email = forms.EmailField(required=True, max_length=100)