上一篇已經完成了polls的基本功能,接下來完善剩下的vote功能和並使用generic views改進請求處理view。包含表單的簡單運用和前後臺參數傳遞。 目錄 vote:完善投票功能 generic views:改進views.py vote 編輯detail.html,添加投票投票功能 添加 ...
上一篇已經完成了polls的基本功能,接下來完善剩下的vote功能和並使用generic views改進請求處理view。包含表單的簡單運用和前後臺參數傳遞。
目錄
- vote:完善投票功能
- generic views:改進views.py
vote
編輯detail.html,添加投票投票功能
<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>
- 添加了form表單,使用post提交,提交到的地址是polls:vote代表一個地址,比如:http://127.0.0.1:8000/polls/4/vote/.
- 這裡涉及到了表單提交,添加{% csrf_token %}防止csrf攻擊,原理就是每次使用的token不一致,導致無法進行偽造請求,從而防止。
- forloop.counter是for迴圈的計數器。
編輯views.py添加投票功能,註意引入相關的類
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): return render(request, 'polls/detail.html', { 'question': question, 'error_message':"you did`t select choice.", }) else: selected_choice.votes += 1 selected_choice.save() return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
request.POST['choice']從post請求裡面獲取前臺傳遞過來的參數,request.POST 是一個dictionary,鍵是參數名,值是參數值,檔案如果是get請求的話就是request.GET
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))在投票成功之後將頁面進行了重定向,防止用戶使用瀏覽器的回退功能之後重覆提交表單
到現在為止功能已經完成了,可以進行測試了,啟動伺服器然後測試相關功能
generic views
對於很多web app來說,需要展示內容的方式相近,比如:查看某個列表,查看某一個的具體內容等等,為此Django提供了generic views——Django詮釋了什麼是快速便捷開發!
使用generic views改寫views.py
from django.shortcuts import render, get_object_or_404 from django.http import HttpResponse, Http404, HttpResponseRedirect from models import Question, Choice from django.views import generic from django.core.urlresolvers import reverse # Create your views here. class IndexView(generic.ListView): template_name = 'polls/index.html' context_object_name = 'latest_question_list' def get_queryset(self): return Question.objects.order_by('-publ_date')[:5] class DetailView(generic.DetailView): model = Question template_name = 'polls/detail.html' class ResultsView(generic.DetailView): model = Question template_name = 'polls/results.html' 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): return render(request, 'polls/detail.html', { 'question': question, 'error_message':"you did`t select choice.", }) else: selected_choice.votes += 1 selected_choice.save() return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
我們將index,detail,result都改寫了,使用到了ListView和DetailView。
IndexView覆寫了get_quesryset方法來實現我們自己的邏輯,設置了模板頁面和返回的參數名稱
DetailView設置了展示詳細信息所需要的model和模板頁面
既然使用了generic views就需要改寫urls.py
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]+)/detail/$', 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'), ]
為了使用generic views把參數名稱改為pk,因為在DetailView裡面已經使用了該名稱——這就是約定優於配置。
總結
整個程式基本寫完了,我們回過頭來發現,我們自己真正寫了的代碼真不多,基本都是依賴Django完成的。可見使用Django快速建站還是有道理的。
完整代碼
http://pan.baidu.com/s/1o8zqGhs