Django incluye la aplicación django.contrib.localflavor que agrupa campos de formulario y widgets específicos para distintos países. Vamos a ver lo que podemos hacer con el "local flavor" para España.
Podemos utilizar el campo es.forms.ESIdentityCardNumberField para validar la entrada comprobando si se trata de un NIF (españoles), NIE (extranjeros) o CIF (empresas) válido.
El campo es.forms.ESCCCField permite validar si la entrada es un número de cuenta bancaria verificando que se trata de un Código Cuenta Cliente correcto. El formato debe ser EEEE-OOOO-CC-AAAAAAAAAA siendo E, O, C y A los dígitos de entidad bancaria, número de oficina, código de control y número de cuenta. El delimitador entre los dígitos puede ser un guión, un espacio o puede no usarse delimitador alguno.
El campo es.forms.ESPhoneNumberField permite validar números de teléfono españoles. Los números deben de tener 9 cifras siendo la primera de ellas 6, 8 ó 9.
El campo es.forms.ESPostalCodeField permite validar códigos postales de España. Los códigos deben de tener 5 cifras, las primeras dos representan el número de provincia y deben estar entre 01 y 52.
Además de los campos de formularios también se incluyen dos widgets que permiten seleccionar provincias y regiones de España en formularios.
El widget es.forms.ESProvinceSelect consiste en un elemento select con todas las provincias de España.
El widget es.forms.ESRegionSelect consiste en un elemento select con todas las comunidades autónomas.
Vamos a ver cómo crear un sencillo formulario en el que usuario tenga que introducir su nombre, su NIF/NIE/CIF, un número de teléfono, una provincia, un código postal y una cuenta bancaria:
from django import forms
from django.contrib.localflavor.es.forms import *
class Formulario(forms.Form):
nombre = forms.CharField(max_length=80)
nif = ESIdentityCardNumberField()
tel = ESPhoneNumberField()
provincia = forms.SelectField(widget=EsProvinceSelect())
codigo_postal = ESPostalCodeField()
cuenta = ESCCCField()
Publicado por Antonio Melé el Viernes 9 d Julio d 2010 | 2 comentarios | Categorías: forms, internacionalización
¿Quieres luchar contra el SPAM en tus formularios sin tener que modificarlos? Una forma sencilla de evitar gran parte del SPAM automático son los snippets AntiSpamForm y AntiSpamModelForm. Están basados en los formularios anti-spam que utiliza la aplicación django.contrib.comments.
Utilizarlos es tan sencillo como guardarlos en nuestro proyecto (por ejemplo en un archivo llamado antispam_forms.py) y usarlos en la definición de nuestros formularios:
from antispam_forms import AntiSpamForm
class MiFormulario(AntiSpamForm):
# campos del formulario...
AntiSpamForm y AntiSpamModelForm utilizan tres métodos para prevenir el SPAM:
Un campo oculto timestamp que adquiere la fecha actual cuando se renderiza el formulario y que se controla en el envío del formulario para evitar envíos excesivamente rápidos (menos de 5 segundos) que generalmente son automáticos. También evita envíos retrasados (más de 2 horas) que pueden ser realizados por bots que primero guardan el formulario y lo tratan de enviar en algún otro momento.
Un campo oculto de hash de seguridad que se genera a partir del timestamp y del setting SECRET_KEY. El hash de seguridad enviado se compara con el hash de seguridad esperado cuando se envía el formulario para rechazar envíos que no incluyan el hash adecuado.
Un campo honeypot que utiliza un CSS display:none; para evitar ser mostrado en el navegador. Los usuarios no lo verán pero la mayoría de spambots tratarán de rellenarlo. El campo honeypot no será validado correctamente si contiene alguna información.
Publicado por Antonio Melé el Jueves 8 d Julio d 2010 | 1 comentario | Categorías: forms, snippets, spam
El campo de formulario ModelChoiceField sirve para permitir la selección de un elemento entre los objetos resultantes de una QuerySet. La QuerySet inicial puede definirse en el propio campo del formulario. Un ejemplo de uso en nuestro forms.py sería:
from django import forms
from django.contrib.auth.models import User
class MiFormulario(forms.Form):
usuario = forms.ModelChoiceField(queryset=User.objects.all())
En este ejemplo nuestro formulario tiene un campo usuario que permite seleccionar un usuario entre todos los registrados. Sin embargo a veces necesitamos que la QuerySet sea distinta de la predefinida en el formulario. Vamos a ver cómo definir la QuerySet dinámicamente al crear un objeto de formulario.
Para definirla dinámicamente primero cambiamos la QuerySet inicial por una QuerySet vacía. El campo ModelChoiceField espera que le pasemos una QuerySet pero aún no sabemos qué QuerySet queremos ejecutar (la generaremos dinámicamente al crear cada objeto de formulario) por lo que primero usamos el método none() que devuelve una lista vacía:
usuario = forms.ModelChoiceField(queryset=User.objects.none())
A continuación sobreescribimos el método __init__ del formulario para poder definir la QuerySet dinámicamente cuando se crea un formulario. Imaginemos que queremos crear una vista que contenga el formulario y que permita seleccionar cualquier usuario que no sea staff. Sin embargo si un superusuario accede a la vista queremos permitirle seleccionar cualquier usuario (incluyendo los que forman parte del staff). Éste es un ejemplo donde necesitamos definir la QuerySet en el momento de crear el formulario:
class MiFormulario(forms.Form):
usuario = forms.ModelChoiceField(queryset=User.objects.none())
def __init__(self, user, *args, **kwargs):
super(MiFormulario, self).__init__(*args, **kwargs)
if user.is_superuser:
self.fields['usuario'].queryset = User.objects.all()
else:
self.fields['usuario'].queryset = User.objects.filter(is_staff=False)
Como podemos ver, el método __init__ recibe un parámetro user. Si el usuario que recibe es superusuario el campo ModelChoiceField del formulario se construirá con la lista de todos los usuarios. De lo contrario se construirá con la lista de usuarios que no forman parte del staff del sitio web. Al crear el formulario en nuestra vista pasaremos request.user al formulario para que se construya con la QuerySet adecuada en función del usuario activo:
from forms import MiFormulario
def mi_vista(request):
mi_form = MiFormulario(user=request.user)
# ...
¡Listo! La QuerySet del campo usuario será una u otra en función de si el usuario que accede a la vista es superusuario o no. Hemos construído la QuerySet de un ModelChoiceField dinámicamente :)
Publicado por Antonio Melé el Viernes 7 d Agosto d 2009 | 10 comentarios | Categorías: fields, forms, trucos
Actualización/Update: Zack translated this post into english and it is available here.
A veces tenemos que modificar información relativa a dos o más modelos distintos desde un solo formulario HTML. Es algo común por ejemplo cuando definimos un perfil de usuario y necesitamos que se pueda modificar la información del modelo User del sistema de autenticación de Django y la información de nuestro modelo de perfil simultáneamente. Vamos a ver cómo puede hacerse. Para seguir este ejemplo necesitaremos tener django.contrib.auth entre las aplicaciones instaladas de nuestro proyecto (setting INSTALLED_APPS).
Suponemos un modelo Perfil como el siguiente definido en nuestro models.py:
from django.db import models
class Perfil(models.Model):
user = models.OneToOneField(User, unique=True, related_name='perfil')
telefono = models.PositiveIntegerField()
direccion = models.TextField()
A continuación creamos un ModelForm para este modelo Perfil y otro para el modelo User del sistema de autenticación de Django. Más adelante usaremos conjuntamente ambos ModelForms en un único formulario HTML. Guardamos el siguiente código en forms.py:
from django import forms
from models import Perfil
from django.contrib.auth.models import User
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email')
class PerfilForm(forms.ModelForm):
class Meta:
model = Perfil
Como podemos ver sólo queremos editar los campos username, first_name, last_name y email del modelo User.
Ahora creamos la vista que generará el formulario para editar el perfil de un usuario. Para ello necesitaremos crear una instancia de los dos ModelForms que hemos definido anteriormente. Nuestro views.py debe tener la siguiente pinta:
from django.shortcuts import render_to_response
from django.template import RequestContext, loader
from django.contrib.auth.decorators import login_required
from forms import PerfilForm, UserForm
@login_required
def editar_perfil(request):
if request.method == 'POST':
# formulario enviado
user_form = UserForm(request.POST, instance=request.user)
perfil_form = PerfilForm(request.POST, instance=request.user.perfil)
if user_form.is_valid() and perfil_form.is_valid():
# formulario validado correctamente
user_form.save()
perfil_form.save()
return HttpResponseRedirect('/formulario-guardado/')
else:
# formulario inicial
user_form = UserForm(instance=request.user)
perfil_form = PerfilForm(instance=request.user.perfil)
return render_to_response('editar_perfil.html', { 'user_form': user_form, 'perfil_form': perfil_form }, context_instance=RequestContext(request))
Utilizamos el decorator @login_required ya que nuestros usuarios deberán estar autenticados para poder modificar su perfil. Si la petición llega por el método POST significa que se ha enviado el formulario y creamos dos Forms, uno para el modelo de usuario y otro para el del perfil, a partir de los datos recibidos. Validamos ambos formularios para guardarlos al igual que hacemos normalmente con un sólo formulario. Utilizamos una plantilla llamada editar_perfil.html a la que le pasamos ambos formularios a través de las variables user_form y perfil_form. El formulario de nuestra plantilla HTML será así de sencillo:
<form action="" method="post">
{{ user_form }}
{{ perfil_form }}
<input type="submit" value="Guardar cambios">
</form>
Con esto generaremos un formulario HTML que tiene primero los campos del modelo User seguidos por los campos del modelo Perfil asociado y que guardará correctamente cualquier cambio realizado en cualquiera de los dos objetos.
Publicado por Antonio Melé el Lunes 6 d Abril d 2009 | 7 comentarios | Categorías: auth, forms, trucos, tutorial
Suscríbete a nuestro feed RSS y al feed de la comunidad para estar al tanto de todo lo que ocurre entorno a Django.
Tú también puedes escribir en éste blog. Para hacerlo basta con que nos digas sobre qué quieres escribir un artículo relacionado con Django.
Utilizar un formulario para modificar 2 modelos
Descubriendo objetos similares por sus etiquetas