一、概述
用户请求到视图流程:
当有人访问我们django项目的时候 例如127.0.0.1:8000/polls/23,django首先到加载mysite.urls模块
在mysite.urls中发现有
urlpatterns
变量,于是在其内按顺序进行匹配。当它匹配上了polls
,就到匹配到的polls.urls中进行下一步处理在polls.url中又匹配到了
/
,最终结果就是调用该模式对应的detail视图。
mysite/urls.py
文件
polls/urls.py
文件
polls/views.py
文件
二、模板的命名空间
1、首先,在polls
目录下创建一个新的templates
目录,Django会在它里面查找模板文件。
项目settings.py
文件中的 TEMPLATES
配置项描述了 Django 如何载入和渲染模板。默认的设置文件设置了 DjangoTemplates
后端作为模板引擎,并将 APP_DIRS
设置成了 True。这一选项将会让 DjangoTemplates
在每个 INSTALLED_APPS
文件夹中寻找 "templates
" 子目录。
2、在templates中创建index文件
3、修改视图文件polls/views.py
,让新的index.html
文件生效并且如果请求的问卷ID不存在,那么会弹出一个Http404错误。
以上代码使用快捷方式:get_object_or_404()
就像render函数一样,get_object_or_404()
方法
三、url Names命名空间
当你有多个app的时候Django通过URL name来区分某个APP,在polls/urls.py文件的开头部分,添加一个app_name
的变量来指定该应用的命名空间:
四、form表单
1、修改polls/detail.html
文件,代码如下:
简要说明:
上面的模板显示一系列单选按钮,按钮的值是选项的ID,按钮的名字是字符串"choice"。这意味着,当你选择了其中某个按钮,并提交表单,一个包含数据
choice=#
的POST请求将被发送到指定的url,#
是被选择的选项的ID。这就是HTML表单的基本概念。form标签的action属性和method属性,action表示你要发送的目的url,method表示提交数据的方式,一般分post和get。
forloop.counter
是Django模板系统专门提供的一个变量,用来表示你当前循环的次数,一般用来给循环项目添加有序数标。由于我们发送了一个POST请求,就必须考虑一个跨站请求伪造的安全问题,简称CSRF。Django为你提供了一个简单的方法来避免这个困扰,那就是在form表单内添加一条
{% csrf_token %}
标签,标签名不可更改,固定格式,位置任意,只要是在form表单内。这个方法对form表单的提交方式方便好使。
2、修改polls/views.py文件中的vote函数
简要说明:
request.POST
是一个类似字典的对象,允许你通过键名访问提交的数据。本例中,request.POST[’choice’]
返回被选择选项的ID,并且值的类型永远是string字符串,哪怕它看起来像数字!同样的,你也可以用类似的手段获取GET请求发送过来的数据,一个道理。request.POST[’choice’]
有可能触发一个KeyError异常,如果你的POST数据里没有提供choice键值,在这种情况下,上面的代码会返回表单页面并给出错误提示。在选择计数器加一后,返回的是一个
HttpResponseRedirect
而不是先前我们常用的HttpResponse
。HttpResponseRedirect
需要一个参数:重定向的URL。这里有一个建议,当你成功处理POST数据后,应当保持一个良好的习惯,始终返回一个HttpResponseRedirect
。这不仅仅是对Django而言,它是一个良好的WEB开发习惯。我们在上面
HttpResponseRedirect
的构造器中使用了一个reverse()
函数。它能帮助我们避免在视图函数中硬编码URL。它首先需要一个我们在URLconf中指定的name,然后是传递的数据。例如'/polls/3/results/'
,其中的3是某个question.id
的值。重定向后将进入polls:results
对应的视图,并将question.id
传递给它。白话来讲,就是把活扔给另外一个路由对应的视图去干。
当有人对某个问题投票后,vote()视图重定向到了问卷的结果显示页面。下面我们来写这个处理结果页面的视图函数detail函数(polls/views.py):
还需要写个模板polls/templates/polls/results.html
。(路由、视图、模板、模型!都是这个套路....)
五、使用通用视图,减少代码量
将原来的代码改为通用视图的方法:
修改URLconf设置
删除一些旧的无用的视图
采用基于类视图的新视图
1、修改URLconf
2、修改视图
在这里,我们使用了两种通用视图ListView
和DetailView
(它们是作为父类被继承的)。这两者分别代表“显示一个对象的列表”和“显示特定类型对象的详细页面”的抽象概念。
每一种通用视图都需要知道它要作用在哪个模型上,这通过model属性提供。
DetailView
需要从url捕获到的称为"pk"的主键值,因此我们在url文件中将2和3条目的修改成了
。
默认情况下,DetailView
通用视图使用一个称作/_detail.html
的模板。在本例中,实际使用的是polls/detail.html
。template_name
属性就是用来指定这个模板名的,用于代替自动生成的默认模板名。(一定要仔细观察上面的代码,对号入座,注意细节。)同样的,在results列表视图中,指定template_name
为'polls/results.html'
,这样就确保了虽然resulst视图和detail视图同样继承了DetailView类,使用了同样的model:Qeustion,但它们依然会显示不同的页面。(模板不同嘛!so easy!)
类似的,ListView通用视图使用一个默认模板称为/_list.html
。我们也使用template_name
这个变量来告诉ListView使用我们已经存在的 "polls/index.html"
模板,而不是使用它自己默认的那个。
在教程的前面部分,我们给模板提供了一个包含question
和latest_question_list
的上下文变量。而对于DetailView,question变量会被自动提供,因为我们使用了Django的模型(Question),Django会智能的选择合适的上下文变量。然而,对于ListView,自动生成的上下文变量是question_list
。为了覆盖它,我们提供了context_object_name
属性,指定说我们希望使用latest_question_list
而不是question_list
。