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

Introdução Rápida Django-表单

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

编写一个简单的表单

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

# Filename : example.py
# Copyright : 2020 By w3codebox
# Author by : pt.oldtoolbag.com
# Data : 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 文件的内容如下:

# Filename : example.py
# Copyright : 2020 By w3codebox
# Author by : pt.oldtoolbag.com
# Data : 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):
         # Redisplaya o formulário de votação da questão.
         return render(request, 'polls/detail.html', {
             'question': question,
             'error_message': "Você não selecionou uma escolha.",
         )
     else:
         selected_choice.votes += 1
         selected_choice.save()
         # Sempre retorne um HttpResponseRedirect após lidar com sucesso
         # com dados POST. Isso previne que os dados sejam postados duas vezes se um
         # O usuário clica no botão Voltar.
         return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

Este código contém algumas coisas que ainda não foram abordadas neste tutorial:

request.POST é um objeto semelhante a um dicionário, que permite que você acesse os dados enviados através do nome da chave. Neste caso, request.POST['choice'] retorna o ID do choice escolhido como uma string. Os valores de request.POST sempre são strings. 

Atenção: Django também oferece request.GET para acessar dados GET da mesma forma – mas usamos explicitamente request.POST em nosso código para garantir que os dados possam ser modificados apenas por chamadas POST.

Se os dados POST não fornecerem choice, request.POST['choice'] provocará uma exceção KeyError. O código acima verifica a exceção KeyError e exibe a mensagem de erro do formulário, se não for fornecido choice.

Após a contagem do choice incrementar, o código retorna um HttpResponse de redirecionamento, em vez de um HttpResponse normal. HttpResponseRedirect precisa de um parâmetro: o URL para onde o usuário será redirecionado (veja abaixo-how do we build the URL in this case).}}

as indicated by the Python comments above, an HttpResponse redirect should always be returned after POST data processing is successful

in this example we use the HttpResponseRedirect constructor and the reverse() function. This function helps to avoid hardcoding URLs in views. This is because we want to control and point to the URL pattern's variable part of the view by name. In this case, using the URLconf configuration makes the reverse() call return a string like:

# Filename : example.py
# Copyright : 2020 By w3codebox
# Author by : pt.oldtoolbag.com
# Data : 2020-08-08
'/polls/3/results/'

where3is the value of question.id. Then, this redirected URL will call the last page displayed in the 'results' view.

now visit the URL: http://127.0.0.1:8000/polls/1/ get the results as shown below:   when someone votes on a question, the vote() view redirects to the results page of that question. Let's write this view (polls/views.py):

# Filename : example.py
# Copyright : 2020 By w3codebox
# Author by : pt.oldtoolbag.com
# Data : 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})

now,create a polls/results.html (polls/templates/polls/results.html)Template:

# Filename : example.py
# Copyright : 2020 By w3codebox
# Author by : pt.oldtoolbag.com
# Data : 2020-08-08
<h2>{{ question.question_text }}</h2>
 <ul>
 {% for choice in question.choice_set.all %}
     <li>{{ choice.choice_text }} -- {{ votes }} voto{{ votes|pluralize }}</li>
 {% endfor %}
 </ul>
 <a href="{% url 'polls:detail' question.id %}">Votar novamente?</a>

Agora, abra o navegador e acesse /polls/1/ E a questão votada deve ser atualizada na página de resultados a cada voto. Se você enviar o formulário sem selecionar uma opção, deve ver uma mensagem de erro. Ao selecionar uma opção e submeter, os seguintes resultados serão exibidos:  

Usar Visões Genéricas: Menos Código é Melhor

Modifique a Configuração de URL

Primeiro, abra polls/urls.py e modifique conforme abaixo:

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'),
]