English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Entrada rápida en Django-表单

在上一节的教程中,我们介绍了 Django的视图,并编写了一个简单的实例。本小节我们将学习网络投票应用程序,并将侧重于简单的表单处理,以最少代码代码量来实现。

编写一个简单的表单

让我们更新 poll detail 模板(“polls/detail.html) ,从上个教程,在模板 polls/templates/polls/detail.html 包含一个HTML<form>元素:

# Nombre de archivo : example.py
# Derechos de autor : 2020 Por w3codebox
# Autor por : es.oldtoolbag.com
# Fecha : 2020-08-08
<h1{{ question.question_text }}</h1>
 {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
 <form action="{% url 'polls:vote' question.id %}" method="post">
 {% csrf_token %}
 {% for choice in question.choice_set.all %}
     <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
     <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label>/label><br />
 {% endfor %}
 <input type="submit" value="Vote" />
 </form>上面的模板显示每个问题选择一个单选按钮。每个单选按钮的值与问题的选择编号相关联。每个单选按钮的名称是“choice”。这意味着,当有人选择了一个单选按钮并提交表单时,它会发送POST数据choice=#,其中#是被选择的选择的ID。这是HTML表单的基本概念。  
  我们设置表单的动作 {% url 'polls:vote' question.id %},以及设置 method="post". 使用 method="post"(相对于 method="get")是非常重要的,因为提交此表单将改变服务器端数据的行为。当创建一个会改变服务器端数据的表单时,使用 method="post". 这篇文章不仅仅针对 Django;这是一个很好的 Web 开发实践。  
  forloop.counter表示表单标签通过了多少次循环  
  因为我们正在创建一个POST形式(可能会影响数据),我们需要担心跨站点请求伪造。但是也不必担心,因为Django自带了一个非常容易使用的保护系统来对抗这种伪造。总之,这是针对内部URL的所有POST形式应该使用{%csrf_token%}模板标签。

我们还创建了一个虚拟实现 vote() 函数。现在创建一个实用的版本。将以下代码添加到文件 polls/views.py:

polls/views.py 文件的内容如下:

# Nombre de archivo : example.py
# Derechos de autor : 2020 Por w3codebox
# Autor por : es.oldtoolbag.com
# Fecha : 2020-08-08
from django.shortcuts import get_object_or_404, render
 from django.http import HttpResponseRedirect, HttpResponse
 from django.core.urlresolvers import reverse
 from models import Choice, Question
 # ...
 def vote(request, question_id):
     question = get_object_or_404(Question, pk=question_id)
     try:
         selected_choice = question.choice_set.get(pk=request.POST['choice'])
     except (KeyError, Choice.DoesNotExist):
         # Redisplayar el formulario de votación de preguntas.
         return render(request, 'polls/detail.html', {
             'question': question,
             'error_message': "No seleccionaste una opción.",
         )
     else:
         selected_choice.votes += 1
         selected_choice.save()
         # Siempre devuelva un HttpResponseRedirect después de manejar con éxito
         # con datos POST. Esto previene que los datos se envíen dos veces si un
         # El usuario hace clic en el botón Atrás.
         return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

Este código contiene varias cosas que aún no se han abordado en este tutorial:

request.POST es un objeto similar a un diccionario que le permite acceder a los datos presentados mediante el nombre de la clave. En este caso, request.POST['choice'] devuelve el ID de la elección seleccionada como cadena. Los valores de request.POST siempre son cadenas. 

Nota: Django también proporciona request.GET para acceder de la misma manera a los datos GET – pero usamos explícitamente request.POST en nuestro código para asegurarnos de que los datos solo se pueden modificar a través de llamadas POST.

Si los datos POST no proporcionan elección, request.POST['choice'] desencadenará una excepción KeyError. El código anterior verifica la excepción KeyError y muestra un mensaje de error si no se proporciona choice.

Después de que el recuento de elección se incrementa, el código devuelve HttpResponse redirección en lugar de un HttpResponse normal. HttpResponseRedirect requiere un parámetro: la URL a la que el usuario será redirigido (ver más abajo)-¿Cómo construimos la URL en este caso)。

Como indica el comentario de Python anterior, siempre debe devolver un HttpResponse redirigido después de que se procesen con éxito los datos POST.

En este ejemplo, utilizamos la función HttpResponseRedirect del constructor reverse(). Esta función ayuda a evitar la codificación dura de URL en las vistas. Porque queremos controlar y apuntar a la parte variable del nombre del patrón de URL de la vista a la que apunta. En este caso, el uso de la configuración URLconf hace que la llamada reverse() devuelva una cadena como:

# Nombre de archivo : example.py
# Derechos de autor : 2020 Por w3codebox
# Autor por : es.oldtoolbag.com
# Fecha : 2020-08-08
'/polls/3/results/'

donde3es el valor de question.id. Luego, esta URL de redirección llamará a la última página de la vista 'results'.

ahora acceda a la dirección: http://127.0.0.1:8000/polls/1/ obtenemos los resultados como se muestra a continuación:   cuando alguien vota en una pregunta, la vista vote() redirige a la página de resultados de la pregunta. Vamos a escribir esta vista (polls/views.py):

# Nombre de archivo : example.py
# Derechos de autor : 2020 Por w3codebox
# Autor por : es.oldtoolbag.com
# Fecha : 2020-08-08
from django.shortcuts import get_object_or_404, render
 def results(request, question_id):
     question = get_object_or_404(Question, pk=question_id)
     return render(request, 'polls/results.html', {'question': question})

ahora, crear un polls/results.html (polls/templates/polls/Plantilla: results.html)

# Nombre de archivo : example.py
# Derechos de autor : 2020 Por w3codebox
# Autor por : es.oldtoolbag.com
# Fecha : 2020-08-08
<h2{{ question.question_text }}</h2>
 <ul>
 {% for choice in question.choice_set.all %}
     <li>{{ choice.choice_text }} -- vote{{ choice.votes|pluralize }}</li>
 {% endfor %}
 </ul>
 <a href="{% url 'polls:detail' question.id %}">Votar de nuevo?</a>

Ahora, abre en el navegador /polls/1/ Y el problema de votación debería actualizarse en la página de resultados cada vez que se vote. Si no seleccionas una opción al enviar el formulario, deberías ver un mensaje de error. Al seleccionar una opción y enviar, se mostrará el siguiente resultado:  

Usa vistas genéricas: menos código es mejor

Modifica la configuración de URL

Primero, abre polls/urls.py y modificarlo como sigue:

from django.conf.urls import url
from . import views
app_name = 'polls'
urlpatterns = [
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
    url(r'^(?P<pk>[0-9]+)/results/$', views.ResultsView.as_view(), name='results'),
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]