DJANGO - CONSTUIR UNA VISTA CON FORMULARIO

En esta sesión demostramos la construcción de una vista con un formulario sencillo, definido desde la propia plantilla de Django, y cómo procesar el envío de los datos usando el patrón redirect-after-post.

Cargando video...

NOTA: Solo puedes ver una versión limitada del video a baja resolución, si quieres ver la versión completa por favor regístrate y obtén alguno de nuestros planes!

Descripción del Vídeo

Construiremos un formulario sencillo para registrar un "voto" en una pregunta y la acción (vista) que procese su envío, teniendo en cuenta:

La construcción adecuada de la URL a la que se envía el formulario

El token para prevenir ataques Cross-Site Request Forgeries (CSRF)

Validaciones sencillas en la lógica de la vista

Posibles casos de fallas por concurrencia

El patrón redirect-after-post: hacer una redirección HTTP (en este caso, a la página de resultados) luego de enviar el formulario para evitar la doble acción al navegar "Atrás".

Código disponible en:
https://github.com/networkfaculty/Fundamentos-Django/releases/tag/d-2.3.4

curso/encuestas/views.py

from django.shortcuts import get_object_or_404, render
from django.http import HttpResponse
from .models import Pregunta, Opcion
from django.http import Http404, HttpResponseRedirect
from django.db.models import F
from django.core.urlresolvers import reverse
def index(request):
preguntas_recientes = Pregunta.objects.order_by('-fe_publicacion')[:5]
context = {'preguntas_recientes': preguntas_recientes,
'titulo': 'Listado de Encuestas' }
return render(request, 'encuestas/index.html', context)
def detalle(request, id_pregunta):
pregunta = get_object_or_404( Pregunta, pk=id_pregunta )
return render(request, 'encuestas/detalle.html', {'pregunta': pregunta})
def votar(request, id_pregunta):
pregunta = get_object_or_404( Pregunta, pk=id_pregunta )
try:
# Nos aseguramos de que el código de la opción recibida esté dentro de las
# opciones registradas para la pregunta
opcion_seleccionada = pregunta.opcion_set.get(pk=request.POST['opcion'])
# Incrementamos la cantidad de votos para la opción seleccionada, pero desde la
# base de datos directamente
# opcion_seleccionada.votos += 1 # Esto puede generar problemas en transacciones
# concurrentes
opcion_seleccionada.votos = F('votos') + 1
opcion_seleccionada.save()
# Nota: Lo anterior también podría escribirse de forma compacta como:
# opcion_seleccionada.update( votos = F('votos') + 1 )
# Luego de guardar exitosamente, redireccionamos a página de resultados.
# Utilizamos 'reverse' para obtener de manera reutilizable la URL de la vista a
# la que queremos redirigir al usuario.
return HttpResponseRedirect(reverse('encuestas:resultados',
kwargs={'id_pregunta': pregunta.id}))
except (KeyError, Opcion.DoesNotExist):
# En caso de un código incorrecto o faltante de opción, volver a mostrar el formulario
return render(request, 'encuestas/detalle.html', {
'pregunta': pregunta,
'mensaje_error': "Opción faltante o inválida",
})
def resultados(request, id_pregunta):
pregunta = get_object_or_404( Pregunta, pk=id_pregunta )
return render(request, 'encuestas/resultados.html', {'pregunta': pregunta})
-curso/encuestas/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
# ej: /encuestas/
url(r'^$', views.index, name='index'),
# ej: /encuestas/5
url(r'^(?P\d+)/$', views.detalle, name='detalle'),
# ej: /encuestas/5/resultados
url(r'^(?P\d+)/resultados$', views.resultados, name='resultados'),
# ej: /encuestas/5/votar
url(r'^(?P\d+)/votar$', views.votar, name='votar'),
]

curso/encuestas/templates/encuestas/detalle.html

{% extends 'encuestas/base.html' %}
{% block encabezado %}

Detalle de Encuesta: {{ pregunta.texto_pregunta|truncatewords:5|escape }}...

{% endblock encabezado %} {% block contenido %} {% if mensaje_error %}

{{ mensaje_error }}

{% endif %}

{{ pregunta.texto_pregunta|escape }}

{% csrf_token %} {% for opcion in pregunta.opcion_set.all %}
{% endfor %}
Ver resultados {% endblock contenido %} -curso/encuestas/templates/encuestas/resultados.html {% extends 'encuestas/base.html' %} {% block encabezado %}

Resultados de Encuesta: {{ pregunta.texto_pregunta|truncatewords:5|escape }}...

{% endblock encabezado %} {% block contenido %}

{{ pregunta.texto_pregunta|escape }}

    {% for opcion in pregunta.opcion_set.all %}
  • {{ opcion.texto_opcion }} -- {{ opcion.votos }} voto(s)
  • {% endfor %}
Votar {% endblock contenido %}

Rating

Global

Ver video en playlist

comments powered by Disqus

Headshot of Juan Paredes

Juan Paredes

Ingeniero de Sistemas con amplia experiencia, especializado en el desarrollo y arquitectura de software.