2011-09-26 12 views
14

que tienen este campo de formulario:¿Cómo obtengo los formularios Django para mostrar el atributo requerido html?

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

que tiene el atributo necesario, pero en el html no es añadiendo el atributo HTML required. De hecho, ni siquiera usa email como tipo de campo, está usando text ... aunque parece obtener max_length 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 obtener Django utilizar los atributos correctos en formularios HTML?

Respuesta

6

Monkeypatching Widget es su 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 
+3

¡¡¡Oye gracias !! –

+4

Podría sugerirle que cambie la instrucción if para que diga: 'si self.is_required y escriba (self) not in (AdminFileWidget, HiddenInput, FileInput) y" __prefix__ "no en attrs [" name "]:' Eso evitará el navegador agrega 'required =" true "' cuando un objeto ya tiene un archivo adjunto, y omite los campos ocultos "simulados" creados para las cosas de administración de StackedInline y TabbedInline. –

16

Los elementos de formulario de Django están escritos contra <input /> como existe en HTML 4, donde type="text" era la opción correcta para las direcciones de correo electrónico. Tampoco hubo required="true".

Si desea atributos HTML personalizados, necesita el argumento de 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' }), 
) 

Se puede extraer más documentación sobre los widgets here. La discusión de attrs está cerca de la parte inferior de esa página.

Con respecto a type="email", puede enviarlo a su attrs diccionario y Django anulará de manera inteligente su valor predeterminado. Si ese no es el resultado que obtiene, entonces su ruta es a la subclase forms.TextInput y luego la pasa al argumento de palabra clave widget.

+0

¿Hay alguna forma de parche de mono en la clase base del widget de formulario? Parece muy poco seco tener que especificar el atributo requerido dos veces. –

+0

Supongo. Es 'django.forms.BaseForm'. –

7

Combinando Daniel y Daniel respuestas, por lo general utilizar este mixin para mis formas:

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 += ' *' 

Así que cuando tengo que crear un nuevo formulario o modelo simplemente uso:

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

En mi caso, obtuve el 'Objeto del formulario no tiene atributos' campos '' porque python evalúa '__init__' de izquierda a derecha y el objeto de formulario no estaba disponible en el momento de la llamada HTML5RequiredMixin '__init__'. Después de cambiar el orden de la declaración de clase como esta y parte de __init__ de NewForm funcionó. 'clase NewForm (forms.Form, HTML5RequiredMixin)', luego __init__ de NewForm, llamada 'HTML5RequiredMixin .__ init__' – Hobaak

5

También existe 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.

4

Como se habrá dado cuenta, establecer su atributo de campo requerido en True es solo para la validación de back-end, como se explica en el Django documentation.

Lo que realmente quiere es añadir un atributo necesario para la Widget del campo:

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

Pero si realmente quiere escribir elegante código, seca, se debe hacer una clase de formulario de base que se ve de forma dinámica para todos los campos requeridos y modifica su atributo necesario Reproductor para usted (puede que el nombre lo que quieran, pero "BaseForm" parece 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" 

y luego tener todos sus objetos Form descienden 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) 
3

Desde Django 1.10, esto está incorporado.

Desde el release notes:

campos de formulario obligatorios ahora tienen el atributo HTML necesario. Establezca el nuevo atributo Form.use_required_attribute en False para deshabilitarlo.

+0

Muchas gracias, he tenido problemas para configurar este atributo durante bastante tiempo. – quapka

Cuestiones relacionadas