看了劉江老師教程這麼多天,卧槽,我才發現他也曾躋身於行伍之間,interesting 劉老師這波講解很到位,告訴你如何編寫單例視圖的時候忽然告訴你,其實不用這麼麻煩,我們有通用視圖,那些總是要做相似的行為的視圖,咱們就寫一個好了,解放生產力不就是進步嗎? 好的廢話不說進入正題,先修改一波detail ...
看了劉江老師教程這麼多天,卧槽,我才發現他也曾躋身於行伍之間,interesting
劉老師這波講解很到位,告訴你如何編寫單例視圖的時候忽然告訴你,其實不用這麼麻煩,我們有通用視圖,那些總是要做相似的行為的視圖,咱們就寫一個好了,解放生產力不就是進步嗎?
好的廢話不說進入正題,先修改一波detail.html模板
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>detail</title> </head> <body> <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> </body> </html>
解讀一些這個html,
h1是一級標題,裡面用了傳入的question對象的question_text屬性,在本實例之中得到的就是問題的名字
接下來用了判斷,這裡看就是關於報錯信息的,如果有,則會出現一句加粗的提示,內容就是。。。報錯信息
接下來是一個文本框,radio類型是單選按鈕,label裡面for屬性表示的是關聯哪個表單,這裡我們看到input文本框的id和for的值是相同的,也就是為label和此處的input做了綁定,於是你就get到了此處顯示的信息為:
問題名
選項1
選項2
按鈕VOTE
回顧一下我們已有的有靈魂和軀體的家伙們(有views中定義且有對應路由渲染模板)index、detail、results
那麼這個vote呢?vote這裡它就是個靈魂,就是個賈維斯,我們不需要它有一個軀殼它就可以完成使命!也就是說它做邏輯業務
現在對views.py中的vote功能進行改寫
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 didn't select a choice.", }) else: selected_choice.votes += 1 selected_choice.save() return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
那麼results就需要模板,在polls/templates/polls/下創建新的html文件results.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>{{ question.question_text }}</h1> <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 %}">Vote again?</a> </body> </html>
註意這裡返回的對象不再是HttpResponse對象而是進行了重定向,跳轉到結果頁面
當我們在detail提交表單就會跳轉執行vote函數,緊接著vote通過判斷被傳入的id對資料庫進行操作即votes屬性(欄位)+1,保存,跳轉結果
為瞭解決冗餘,引入通用視圖
修改views.py
from django.shortcuts import render, get_object_or_404 from django.http import HttpResponse, Http404, HttpResponseRedirect from django.template import loader from django.urls import reverse from django.views import generic from .models import Question, Choice # def index(request): # return HttpResponse("hello world,you are at the polls index!") class IndexView(generic.ListView): template_name = 'polls/index.html' context_object_name = 'latest_question_list' def get_queryset(self): """Return the last five published question.""" return Question.objects.order_by('-pub_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 didn't select a choice.", }) else: selected_choice.votes += 1 selected_choice.save() return HttpResponseRedirect(reverse('polls:results', args=(question.id,))) # Create your views here.
generic.ListView(顯示一個對象列表)和DetailView(顯示詳細內容)是django兩個通用視圖類,這裡在創建我們自己的視圖的時候繼承了這兩個父類
由於DetailView需要從url中獲取名為pk的主鍵值,所以在urls中修改了question_id為pk。
DetailView視圖預設使用一個叫做<app name>/<model name>_detail.html的模板,而此處我們選喲用自己的模板,template_name這個屬性就是告訴django我們的預設模板是什麼,通過具體指定。
對於ListView視圖來說預設模板我們用自己的和Detail雷同的方式,但是對於Listview視圖來說預設傳遞信息的上下文變數是question_list,這裡由於我們的頁面index中設置的上下文變數叫做
latest_question_list,所以我們需要通過設置context_object_name屬性來覆蓋。
當你更改了views後,這時候需要對urls也重新配置
polls/urls.py
from django.urls import path from . import views app_name = 'polls' urlpatterns = [ path('', views.IndexView.as_view(), name='index'), # ex:/polls/5 path('<int:pk>/', views.DetailView.as_view(), name='detail'), # ex:/polls/5/results path('<int:pk>/results/', views.ResultsView.as_view(), name='results'), # ex:/polls/5/vote/ path('<int:question_id>/vote/', views.vote, name='vote'), ]
然後你就可以在你的投票界面愉快的玩耍了
試著點選項和Vote試試?
題外話,當你創建了app之後,你的8000埠進入頁面就一直都是404,這是因為有了app之後伺服器從localhost:8000後面開始尋找pysite/urls.py中的配置,它無法找到""這個對應的模板,解決的辦法就是手動給pysite添加views和templates併在urls.py中設置""對應的視圖和名字,然後比如我這個就是這樣: