知识点
1) 表单的编写
CSRF问题
forloop.counter
2) 视图函数的知识
GET和POST
HttpResponseRedirect的使用
reverse的使用
3) 通用视图
CBV(class_base view)
CVB在URLs的配置, 使用as_view()
ListView和DetailView
注意主键获取, 名字用fk
默认模板的问题
自带变量问题
1 编写表单
polls/templates/polls/detail.html
{ { question.question_text }}
{% if error_message %}{ { error_message }}
{% endif %}
表单中的第一个input, type为radio表示单选框, name为choice表示提交的时候该input的value会提交成 choice=值 的形式
form的属性添加了action表示提交地址, method设置为post非常适合用于表单提交数据
forloop.counter表示for循环的次数, 类似于我们常用的i
由于提交的表单会修改数据, 这有可能造成CSRF(Cross Site Request Forgeries, 跨站点请求伪造)
为了防范这类问题, 针对修改内部网站的所有PSOT表达都应该加上{% csrf_token %}
URLs配置如下
polls/urls.py
url(r'^(?P[0-9]+)/vote/$', views.vote, name='vote'),
视图函数编写为
polls/views.py
from django.shortcuts import get_object_or_404, renderfrom django.http import HttpResponseRedirect, HttpResponsefrom django.urls import reversefrom .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): # Redisplay the question voting form. 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,)))
request可以得到GET和POST两个值, 得到的结果是以个类似于字典的值, 可以用 request.GET['名字'] 或者 request.POST['名字'] 的方式来获取值
返回使用的是HttpResponseRedirect 而不是常用的HttpResponse, 其只需传入一个参数, 是用于重定向的地址, 类型是字符串
一般POST成功处理之后都应该使用HttpResponseRedirect, 原因是HttpResponseRedirect可以防止用户在点击回退按钮的时候重复提交表单
可以使用reverse函数来避免硬编码(hardcode )的URL, reverse()函数可以传入两个参数, 一个是视图名, 一个是URL的参数
如果question_id为3 那么返回的URL为
'/polls/3/results/'
现在编写results的视图
polls/views.py
from django.shortcuts import get_object_or_404, renderdef results(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/results.html', {'question': question})
再创建results的模板
polls/templates/polls/results.html
{ { question.question_text }}
- {% for choice in question.choice_set.all %}
- { { choice.choice_text }} -- { { choice.votes }} vote{ { choice.votes|pluralize }} {% endfor %}
注意:
此次的投票系统可能出现一些小BUG
两个使用者可能在同一时刻提交同一个选项, 该选项的计数可能不正确
2 编写通用视图
通过编写通用的视图, 可以复用代码, 进而减少代码量
对于通用视图, Django提供了一个快捷方式, 叫做 通用视图系统( "generic views" system)
具体步骤为
1) 转换URLconf
2) 删除一些旧的,不需要的视图
3) 根据Django的通用视图编写新视图
修改URL配置
polls/urls.pyfrom django.conf.urls import urlfrom polls import viewsapp_name = 'polls'urlpatterns = [ url(r'^$', views.IndexView.as_view(), name='index'), url(r'^(?P[0-9]+)/$', views.DetailView.as_view(), name='detail'), url(r'^(?P [0-9]+)/results/$', views.ResultsView.as_view(), name='results'), url(r'^(?P [0-9]+)/vote/$', views.vote, name='vote'),]
- 注意第二个第三个URL的名字改为了pk
修改视图
polls/views.py
from django.shortcuts import get_object_or_404, renderfrom django.http import HttpResponseRedirectfrom django.urls import reversefrom django.views import genericfrom .models import Choice, Questionclass IndexView(generic.ListView): template_name = 'polls/index.html' context_object_name = 'latest_question_list' def get_queryset(self): """Return the last five published questions.""" 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): # 不做修改
在这当中用到了ListView和DetailView两个通用视图, 分别用于显示
对象列表
特定对象的详细信息
注意两点
1) 必须要设置model, 要为其指定一个表(这里需要用类)
2) 在捕获URL的时候, 需要获得主键信息, 这个时候就需要把正则表达式分组命名为pk, 这样命名Django才能正常识别
默认情况下, DetailView返回的模板名也是有格式的(ListView同理), 格式为
/ _detail.html / _list.html
另外还需要说明的是, 默认会提供一个上下文变量question 和一个全局变量latest_question_list
对于DetailView, 使用模型Question会自动提供变量question
对于ListView, 使用模型Question会自动提供变量question_list
如果要重写这个变量, 可以通过context_object_name属性来完成, index()函数就修改成了last_question_list
context_object_name = 'latest_question_list'
如果需要更多内容,