personalizados - ¿Cómo obtengo los formularios Django para mostrar el atributo html requerido?
meet django (6)
Combinando las respuestas de Daniel y Daniel, normalmente uso esta combinación para mis formularios:
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 += '' *''
Entonces, cuando tengo que crear una nueva forma o modelo, solo uso:
class NewForm(HTML5RequiredMixin, forms.Form):
...
Tengo este campo de formulario:
email = forms.EmailField(
required=True,
max_length=100,
)
Tiene el atributo requerido, pero en el html no está agregando el atributo html required
. De hecho, ni siquiera utiliza el email
como tipo de campo, usa text
... aunque parece que max_length está bien.
Real:
<input id="id_email" type="text" name="email" maxlength="100">
Esperado:
<input id="id_email" type="email" name="email" maxlength="100" required="true">
¿Cómo puedo hacer que Django use los atributos correctos en formularios html?
Como se ha dado cuenta, establecer su atributo Campo requerido en True
es solo para la validación del servidor, tal como se explica en la documentación de Django .
Lo que realmente desea es agregar un atributo requerido al Widget del campo:
email.widget.attrs["required"] = "required"
Pero si realmente desea escribir código DRY elegante, debe crear una clase de formulario base que busque dinámicamente todos los campos requeridos y modifique el atributo requerido de su widget para usted (puede nombrarlo como desee, pero "BaseForm" parece apropiado ):
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"
Y luego haz que todos tus objetos de Forma desciendan de ella:
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)
Desde Django 1.10, esto está incorporado.
De las notas de publicación :
Los campos de formulario requeridos ahora tienen el atributo HTML requerido. Establezca el nuevo atributo Form.use_required_attribute en False para deshabilitarlo.
Los elementos del formulario Django se escriben en contra de <input />
tal como existe en HTML 4, donde type="text"
era la opción correcta para las direcciones de correo electrónico. Tampoco había required="true"
.
Si desea atributos HTML personalizados, necesita el argumento de la palabra clave attrs
para el widget . Se vería algo como esto:
email = forms.EmailField(
max_length=100,
required=True,
widget=forms.TextInput(attrs={ ''required'': ''true'' }),
)
Puedes consultar más documentación sobre widgets here . La discusión de attrs
está cerca de la parte inferior de esa página.
Con respecto a type="email"
, podría enviarlo a su diccionario de attrs
y Django anulará de manera inteligente su valor predeterminado. Si ese no es el resultado que obtiene, entonces su ruta es a los forms.TextInput
subclase. forms.TextInput
y luego lo pasa al argumento de la palabra clave del widget
.
Monkeypatching Widget es tu mejor apuesta:
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
También está la solución de solo plantilla que utiliza un filtro. Recomiendo django-widget-tweaks
:
{% load widget_tweaks %}
{{ form.email|attr:''required:true'' }}
Eso fue fácil.