如何让 Django 表单显示 html 必需的属性?
Posted
技术标签:
【中文标题】如何让 Django 表单显示 html 必需的属性?【英文标题】:How do I get Django forms to show the html required attribute? 【发布时间】:2011-11-25 15:05:30 【问题描述】:我有这个表单域:
email = forms.EmailField(
required=True,
max_length=100,
)
它具有 required 属性,但在 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 表单中使用正确的属性?
【问题讨论】:
【参考方案1】:从 Django 1.10 开始,这是内置的。
来自release notes:
必填表单字段现在具有 required HTML 属性。将新的 Form.use_required_attribute 属性设置为 False 以禁用它。
【讨论】:
非常感谢,很长一段时间我都无法设置此属性。【参考方案2】:如您所见,将 Field required 属性设置为 True
仅用于后端验证,如 Django documentation 中所述。
您真正想要的是在字段的Widget 中添加一个必需的属性:
email.widget.attrs["required"] = "required"
但是,如果您真的想编写优雅的 DRY 代码,您应该创建一个基本表单类,它可以动态查找所有必填字段并为您修改它们的小部件所需属性(您可以随意命名,但是“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)
【讨论】:
【参考方案3】: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
【讨论】:
我是否建议您将 if 语句更改为:if self.is_required and type(self) not in (AdminFileWidget,HiddenInput, FileInput) and "__prefix__" not in attrs["name"]:
这将阻止浏览器在对象已附加文件时添加required="true"
,并跳过为 StackedInline 和 TabbedInline 管理内容创建的隐藏“模拟”字段。【参考方案4】:
还有使用过滤器的纯模板解决方案。我推荐django-widget-tweaks
:
% load widget_tweaks %
form.email|attr:'required:true'
这很容易。
【讨论】:
【参考方案5】:结合 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):
...
【讨论】:
在我的例子中,我得到了 'Form object has no attribute 'fields'' 因为 python 从左到右评估 'init' 并且 form 对象在HTML5RequiredMixin 'init' 调用的时间。在我像这样更改类声明的顺序以及 NewForm 的 init 的一部分之后,它就起作用了。 ' class NewForm(forms.Form, HTML5RequiredMixin) ',然后NewForm的init,调用'HTML5RequiredMixin.__init__'【参考方案6】:Django 表单元素是针对<input />
编写的,因为它存在于 HTML 4 中,其中type="text"
是电子邮件地址的正确选项。也没有required="true"
。
如果您想要自定义 HTML 属性,您需要 widget 的 attrs
关键字参数。它看起来像这样:
email = forms.EmailField(
max_length=100,
required=True,
widget=forms.TextInput(attrs= 'required': 'true' ),
)
您可以查看有关小部件here 的更多文档。 attrs
的讨论位于该页面的底部附近。
关于type="email"
,您可以将其发送到您的attrs
字典,Django 将智能地覆盖其默认值。如果这不是您得到的结果,那么您的路线是继承 forms.TextInput
,然后将其传递给 widget
关键字参数。
【讨论】:
有没有办法给表单小部件基类打补丁?必须指定两次所需的属性似乎非常不干燥。 我想。这是django.forms.BaseForm
。以上是关于如何让 Django 表单显示 html 必需的属性?的主要内容,如果未能解决你的问题,请参考以下文章
如何让所有 django allauth 表单和对话框显示在弹出窗口中