我有这个表单字段:
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表单中使用正确的属性?
答案 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以来,这是内置的。
必填表单字段现在具有必需的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)