Как мне получить формы Django для отображения атрибута html?
У меня есть это поле формы:
email = forms.EmailField(
required=True,
max_length=100,
)
Он имеет обязательный атрибут, но в html он не добавляет атрибут html required
. На самом деле он даже не использует email
в качестве типа поля, используя text
... хотя кажется, что max_length просто отлично.
Actual:
<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
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 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
Ответ 2
Элементы формы Django записываются с помощью <input />
, как он существует в HTML 4, где type="text"
был правильной опцией для адресов электронной почты. Также не было required="true"
.
Если вам нужны пользовательские атрибуты HTML, вам понадобится аргумент ключевого слова attrs
для виджета. Он будет выглядеть примерно так:
email = forms.EmailField(
max_length=100,
required=True,
widget=forms.TextInput(attrs={ 'required': 'true' }),
)
Вы можете посмотреть дополнительную документацию о виджетах здесь. Обсуждение attrs
находится в нижней части этой страницы.
Что касается type="email"
, вы можете отправить его в словарь attrs
, и Django разумно переопределит его значение по умолчанию. Если это не результат, который вы получите, тогда ваш маршрут будет подклассом forms.TextInput
, а затем передать его в аргумент ключевого слова widget
.
Ответ 3
Объединяя ответы Даниила и Дэниела, я обычно использую этот 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):
...
Ответ 4
Также существует только шаблонное решение с использованием фильтра. Я рекомендую django-widget-tweaks
:
{% load widget_tweaks %}
{{ form.email|attr:'required:true' }}
Это было легко.
Ответ 5
Как вы поняли, установка атрибута Field required на True
выполняется только для проверки бэкэнд, как описано в документации Django.
Что вы действительно хотите, так это добавить обязательный атрибут в поле Widget поля:
email.widget.attrs["required"] = "required"
Но если вы действительно хотите написать элегантный, СУХОЙ код, вы должны создать базовый класс формы, который динамически ищет все необходимые поля и изменяет их необходимый атрибут виджета (вы можете называть его любым желаемым, но "BaseForm" кажется apt):
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"
И затем все объекты вашей формы спускаются из него:
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)
Ответ 6
Так как Django 1.10, он встроен.
Из примечания к выпуску:
Обязательные поля формы теперь имеют требуемый атрибут HTML. Установите для нового атрибута Form.use_required_attribute значение False, чтобы отключить его.