English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Nel tutorial dell'ultimo paragrafo, abbiamo presentato Vista Djangoe ha scritto un esempio semplice. In questa sezione impareremo a creare un'applicazione di voto online, concentrandoci sul trattamento dei moduli in modo semplice con il minor numero possibile di codice.
Lasciamo aggiornare il modello di dettaglio del poll ('polls/detail.html'), dal tutorial precedente, nel modello polls/templates/polls/detail.html è presente un elemento HTML<form>:
# Filename : example.py # Copyright : 2020 By w3codebox # Author by : it.oldtoolbag.com # Date : 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><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 : it.oldtoolbag.com # Date : 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): # Ri-disegna il modulo di voto della domanda. return render(request, 'polls/detail.html', { 'question': question, 'error_message': "Non hai selezionato una scelta.", ) else: selected_choice.votes += 1 selected_choice.save() # Restituisce sempre un HttpResponseRedirect dopo aver gestito con successo # con dati POST. Questo impedisce che i dati vengano inviati due volte se un # L'utente preme il pulsante Indietro. return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
Questo codice contiene alcune cose che non sono state trattate nel tutorial fino ad ora:
request.POST è un oggetto simile a dizionario che ti permette di accedere ai dati inviati tramite chiave. In questo caso, request.POST['choice'] restituisce l'ID del choice selezionato come stringa. I valori di request.POST sono sempre stringhe.
Attenzione: Django offre anche request.GET per accedere ai dati GET nello stesso modo – ma utilizziamo esplicitamente request.POST nel nostro codice per assicurarci che i dati possano essere modificati solo tramite chiamate POST.
Se i dati POST non forniscono choice, request.POST['choice'] solleva un'eccezione KeyError. Il codice sopra verifica l'eccezione KeyError e mostra un messaggio di errore per il modulo, se non è stato fornito choice.
Dopo che il conteggio del choice è aumentato, il codice restituisce HttpResponse redirect, invece di un HttpResponse normale. HttpResponseRedirect richiede un parametro: l'URL a cui l'utente sarà reindirizzato (vedi di seguito - come costruiamo l'URL in questo caso).
Come indicato nei commenti Python sopra, dovrebbe sempre essere restituito un HttpResponse reindirizzamento dopo che i dati POST sono elaborati con successo.
In questo esempio, usiamo la costruzione HttpResponseRedirect e la funzione reverse(). Questa funzione aiuta a evitare l'hardcoding di URL nelle viste. Poiché vogliamo controllare e puntare al nome del modello della parte variabile dell'URL del modello della vista, in questo caso, l'uso della configurazione URLconf farà in modo che la chiamata reverse() restituisca una stringa come:
# Filename : example.py # Copyright : 2020 By w3codebox # Author by : it.oldtoolbag.com # Date : 2020-08-08 "/polls/3/results/"
Tra cui 3 è il valore di question.id. Poi, l'URL di reindirizzamento chiamerà l'ultima pagina visualizzata nella vista "results".
Ora, accedi all'indirizzo: http://127.0.0.1:8000/polls/1/ per ottenere i risultati come segue: Quando qualcuno vota su una domanda, la vista vote() reindirizza alla pagina dei risultati della domanda. Scriviamo questa vista (polls/views.py):
# Filename : example.py # Copyright : 2020 By w3codebox # Author by : it.oldtoolbag.com # Date : 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}));
Ora, crea un template polls/results.html (polls/templates/polls/results.html):
# Filename : example.py # Copyright : 2020 By w3codebox # Author by : it.oldtoolbag.com # Date : 2020-08-08 <h2>{{ question.question_text }}</h2> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li> {% endfor %} </ul> <a href="{% url 'polls:detail' question.id %}">Vota di nuovo?</a>
Ora, apri /polls/1/ nel browser e vota per il problema. Dovrebbe vedere aggiornati i risultati ogni volta che voti. Se invii il modulo senza selezionare un'opzione, dovrebbe vedere un messaggio di errore. Se selezioni un'opzione e invii, dovrebbe apparire il seguente risultato:
Prima di tutto, apri polls/urls.py e modifica come segue:
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'), ]