Formularios Django

Los formularios HTML son la forma clásica de interactividad en los sitios web. Este capítulo presentará cómo usar Django para procesar los datos de formularios enviados por los usuarios.


Solicitud HTTP

El protocolo HTTP funciona de manera "solicitud-respuesta". Cuando el cliente envía una solicitud, puede adjuntar datos a la misma. El servidor, al analizar la solicitud, puede obtener los datos enviados por el cliente y proporcionar servicios específicos según la URL.

Método GET

En el proyecto anterior, creamos un archivo search.py para recibir las solicitudes del usuario:

/HelloWorld/HelloWorld/search.py Código del archivo:

from django.http import HttpResponse from django.shortcuts import render # formulario def search_form(request): return render(request, 'search_form.html') # Recibir datos de la solicitud def search(request): request.encoding='utf-8' if 'q' in request.GET and request.GET['q']: message = 'El contenido de tu búsqueda es:' + request.GET['q'] else: message = 'Has enviado un formulario vacío' return HttpResponse(message)

Agrega el formulario search_form.html en el directorio de plantillas templates:

/HelloWorld/templates/search_form.html Código del archivo:

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Tutorial para novatos (example.com)</title> </head> <body> <form action="/search/" method="get"> <input type="text" name="q"> <input type="submit" value="Buscar"> </form> </body> </html>

Modifica las reglas de urls.py de la siguiente manera:

/HelloWorld/HelloWorld/urls.py Código del archivo:

from django.conf.urls import url from . import views,testdb,search urlpatterns = [ url(r'^hello/$', views.ejemplo), url(r'^testdb/$', testdb.testdb), url(r'^search-form/$', search.search_form), url(r'^search/$', search.search), ]

Dirección de accesohttp://127.0.0.1:8000/search-form/Y al buscar, el resultado es el siguiente:

Método POST

Arriba usamos el método GET, donde la visualización de la vista y el procesamiento de la solicitud se manejan en dos funciones separadas.

El método POST se usa más comúnmente al enviar datos. A continuación usaremos este método, y con una URL y una función de procesamiento, mostraremos la vista y procesaremos la solicitud al mismo tiempo.

Creamos post.html en templates:

/HelloWorld/templates/post.html Código del archivo:

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Tutorial para novatos (example.com)</title> </head> <body> <form action="/search-post/" method="post"> {% csrf_token %} <input type="text" name="q"> <input type="submit" value="Buscar"> </form> <p>{{ rlt }}</p> </body> </html>

Al final de la plantilla, agregamos una marca rlt para reservar un lugar para el resultado del procesamiento del formulario.

Después del formulario, también hay una{% csrf_token %}etiqueta. El nombre completo de csrf es Cross Site Request Forgery. Esta es una funcionalidad que Django proporciona para evitar solicitudes de envío disfrazadas. Los formularios enviados con el método POST deben tener esta etiqueta.

En el directorio HelloWorld, crea un nuevo archivo search2.py y usa la función search_post para procesar las solicitudes POST:

/HelloWorld/HelloWorld/search2.py Código del archivo:

# -*- coding: utf-8 -*- from django.shortcuts import render from django.views.decorators import csrf # Recibir datos de solicitudes POST def search_post(request): ctx ={} if request.POST: ctx['rlt'] = request.POST['q'] return render(request, "post.html", ctx)

Modifica las reglas de urls.py de la siguiente manera:

/HelloWorld/HelloWorld/urls.py Código del archivo:

from django.conf.urls import url from . import views,testdb,search,search2 urlpatterns = [ url(r'^hello/$', views.hello), url(r'^testdb/$', testdb.testdb), url(r'^search-form/$', search.search_form), url(r'^search/$', search.search), url(r'^search-post/$', search2.search_post), ]

Visitahttp://127.0.0.1:8000/search-post/El resultado se muestra a continuación:

Después de completar el ejemplo anterior, nuestra estructura de directorios es la siguiente:

HelloWorld
|-- HelloWorld
|   |-- __init__.py
|   |-- __init__.pyc
|   |-- search.py
|   |-- search.pyc
|   |-- search2.py
|   |-- search2.pyc
|   |-- settings.py
|   |-- settings.pyc
|   |-- testdb.py
|   |-- testdb.pyc
|   |-- urls.py
|   |-- urls.pyc
|   |-- views.py
|   |-- views.pyc
|   |-- wsgi.py
|   `-- wsgi.pyc
|-- TestModel
|   |-- __init__.py
|   |-- __init__.pyc
|   |-- admin.py
|   |-- admin.pyc
|   |-- apps.py
|   |-- migrations
|   |   |-- 0001_initial.py
|   |   |-- 0001_initial.pyc
|   |   |-- __init__.py
|   |   `-- __init__.pyc
|   |-- models.py
|   |-- models.pyc
|   |-- tests.py
|   `-- views.py
|-- db.sqlite3
|-- manage.py
`-- templates
    |-- base.html
    |-- hello.html
    |-- post.html
    `-- search_form.html

Objeto Request

El primer parámetro de cada función de vista es un objeto HttpRequest, como en la siguiente función ejemplo():

from django.http import HttpResponse

def ejemplo(request):
    return HttpResponse("Hello world")

El objeto HttpRequest contiene información sobre la URL de la solicitud actual:

Atributo

Descripción

path

La ruta completa de la página solicitada, sin incluir el dominio—por ejemplo, "/hello/".

method

Representación de cadena del método HTTP utilizado en la solicitud. En mayúsculas. Por ejemplo:

if request.method == 'GET':
    do_something()
elif request.method == 'POST':
    do_something_else()

GET

Objeto similar a diccionario que contiene todos los parámetros HTTP GET. Consulta la documentación de QueryDict.

POST

Objeto similar a diccionario que contiene todos los parámetros HTTP POST. Consulta la documentación de QueryDict.

Es posible que el servidor reciba una solicitud POST vacía. Es decir, el formulario envía la solicitud mediante el método HTTP POST, pero el formulario puede no contener datos. Por lo tanto, no se puede usar la sentencia if request.POST para determinar si se utiliza el método HTTP POST; se debe usar if request.method == "POST" (consulta el atributo method de esta tabla).

Nota: POST no incluye información de carga de archivos. Consulta el atributo FILES.

REQUEST

Por conveniencia, este atributo es una combinación de los atributos POST y GET, pero tiene una particularidad: busca primero en el atributo POST y luego en el atributo GET. Se basa en el $_REQUEST de PHP.

Por ejemplo, si GET = {"name": "john"} y POST = {"age": '34'}, entonces el valor de REQUEST["name"] es "john" y el valor de REQUEST["age"] es "34".

Se recomienda encarecidamente usar GET y POST, porque estos dos atributos son más explícitos y el código escrito es más fácil de entender.

COOKIES

Objeto de diccionario estándar de Python que contiene todas las cookies. Las claves y los valores son cadenas.

FILES

Objeto similar a diccionario que contiene todos los archivos subidos. Cada clave en FILES es el valor del atributo name en la etiqueta <input type="file" name="" />. Cada valor en FILES también es un objeto de diccionario estándar de Python que contiene las siguientes tres claves:

  • filename: nombre del archivo subido, representado como una cadena de Python.
  • content-type: tipo de contenido del archivo subido.
  • content: contenido original del archivo subido.

Nota: FILES solo tiene datos si el método de solicitud es POST y la página de solicitud tiene el atributo enctype="multipart/form-data" en el <form>. De lo contrario, FILES es un diccionario vacío.

META

Diccionario que contiene toda la información disponible de los encabezados HTTP. Por ejemplo:

  • CONTENT_LENGTH
  • CONTENT_TYPE
  • QUERY_STRING: la cadena de consulta original sin analizar.
  • REMOTE_ADDR: dirección IP del cliente.
  • REMOTE_HOST: nombre de host del cliente.
  • SERVER_NAME: nombre de host del servidor.
  • SERVER_PORT: puerto del servidor.

En META, estos encabezados con el prefijoHTTP_como clave, y lo que sigue a los dos puntos (:) es el valor. Por ejemplo:

  • HTTP_ACCEPT_ENCODING
  • HTTP_ACCEPT_LANGUAGE
  • HTTP_HOST: información del encabezado HTTP Host enviada por el cliente.
  • HTTP_REFERER: página de referencia.
  • HTTP_USER_AGENT: cadena user-agent del cliente.
  • HTTP_X_BENDER: información del encabezado X-Bender.

user

Es un objeto django.contrib.auth.models.User que representa al usuario actualmente conectado.

Si el usuario visitante no ha iniciado sesión, user se inicializará como una instancia de django.contrib.auth.models.AnonymousUser.

Puedes determinar si el usuario ha iniciado sesión mediante el método is_authenticated() de user:

if request.user.is_authenticated():
    # Do something for logged-in users.
else:
    # Do something for anonymous users.

Este atributo solo está disponible cuando AuthenticationMiddleware de Django está activado.

session

El único atributo de lectura y escritura, representa el objeto de diccionario de la sesión actual. Este atributo solo está disponible cuando el soporte de sesiones de Django está activado.

raw_post_data

Datos HTTP POST originales, sin analizar. Son útiles para el procesamiento avanzado.

El objeto Request también tiene algunos métodos útiles:

MétodoDescripción
__getitem__(key) Devuelve el valor de la clave GET/POST, primero toma POST y luego GET. Si la clave no existe, lanza KeyError.
Esto nos permite acceder al objeto HttpRequest con la sintaxis de diccionario.
Por ejemplo, request["foo"] equivale a intentar primero request.POST["foo"] y luego request.GET["foo"].
has_key() Verificar si request.GET o request.POST contiene la clave especificada por el parámetro.
get_full_path() Devuelve la ruta de la solicitud que contiene la cadena de consulta. Por ejemplo, "/music/bands/the_beatles/?print=true"
is_secure() Devuelve True si la solicitud es segura, es decir, si se realizó mediante una solicitud HTTPS.

Objeto QueryDict

En el objeto HttpRequest, los atributos GET y POST son instancias de la clase django.http.QueryDict.

QueryDict es una clase personalizada similar a un diccionario, que se utiliza para manejar el caso de que una sola clave corresponda a múltiples valores.

QueryDict implementa todos los métodos estándar de diccionario. También incluye algunos métodos específicos:

Método Descripción

__getitem__

Hay una pequeña diferencia con el manejo del diccionario estándar: si la clave corresponde a múltiples valores, __getitem__() devuelve el último valor.

__setitem__

Establece la lista de valores (una lista de Python) para la clave especificada por el parámetro. Nota: solo se puede llamar en un objeto QueryDict mutable (es decir, una copia de un objeto QueryDict creada mediante copy()).

get()

Si la clave corresponde a múltiples valores, get() devuelve el último valor.

update()

El parámetro puede ser un QueryDict o un diccionario estándar. A diferencia del método update del diccionario estándar, este método agrega los items del diccionario, en lugar de reemplazarlos:

>>> q = QueryDict('a=1')

>>> q = q.copy() # to make it mutable

>>> q.update({'a': '2'})

>>> q.getlist('a')

 ['1', '2']

>>> q['a'] # returns the last

['2']

items()

Hay una pequeña diferencia con el método items() del diccionario estándar: este método utiliza __getitem__() con lógica de valor único:

>>> q = QueryDict('a=1&a=2&a=3')

>>> q.items()

[('a', '3')]

values()

Hay una pequeña diferencia con el método values() del diccionario estándar: este método utiliza __getitem__() con lógica de valor único:

Además, QueryDict también tiene algunos métodos, como se muestra en la siguiente tabla:

Método Descripción

copy()

Devuelve una copia del objeto, implementada internamente con copy.deepcopy() de la biblioteca estándar de Python. Esta copia es mutable (modificable), es decir, se pueden cambiar los valores de la copia.

getlist(key)

Devuelve todos los valores correspondientes a la clave del parámetro, como una lista de Python. Si la clave no existe, devuelve una lista vacía. Se garantiza que devuelve una lista de algún tipo.

setlist(key,list_)

Establece el valor de la clave como list_ (a diferencia de __setitem__()).

appendlist(key,item)

Agrega un item a la lista interna asociada con la clave.

setlistdefault(key,list)

Hay una pequeña diferencia con setdefault: acepta una lista en lugar de un solo valor como parámetro.

lists()

Hay una pequeña diferencia con items(): devuelve todos los valores de la clave, como una lista, por ejemplo:

>>> q = QueryDict('a=1&a=2&a=3')

>>> q.lists()

[('a', ['1', '2', '3'])]

urlencode()

Devuelve una cadena formateada como cadena de consulta (por ejemplo: "a=2&b=3&b=5").

Otras extensiones