看了刘江老师教程这么多天,卧槽,我才发现他也曾跻身于行伍之间,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中设置""对应的视图和名字,然后比如我这个就是这样: