5. 视图概述¶
视图即视图模块,接收web请求并返回web响应的事物处理模块
响应指符合http协议要求的任何内容,包括json,string, html等
是django后台的核心内容,一般在每个APP下的views.py文件里面,如果特别复杂可以有别的python文件
视图可以看作一个接受HttpRequest的实例,返回一个Response的类的实例的类或者函数,形如:
def views_func(request): ... ... return HttpResponse(...)
相应的urls中对应的代码应该是:
... ... path("tulingxueyuan/", views.views_func) ... ...
5.1. 简单视图¶
目的:
- 创建一个简单视图函数
- 返回一段html代码
- 利用django.http包中的HttpResponse类
分析:
- HttpResponse是一个由django提供的视图类,可以用来返回简单视图
- HttpRequest尽可能不让程序员改动内容,HttpResponse则需要手动改动内容
- 为了代码简洁,从新创建v3_views项目,添加tuling应用
操作步骤:
启动虚拟环境
> source activate tuling_django
创建项目和app
>django-admin startproject v3_views >cd v3_views >python manage.py startapp tuling
修改配置文件v3/settings.py
每从创建一个APP都应该在settings.py下添加这个APP,否则可能会导致各种问题,简单应用 也可能不影响使用。
添加app,修改完后代码如下:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'tuling', #添加的新的APP ]
配置pycharm让软件能直接运行manage.py函数, 具体配置参看第一张django概述
运行 east/manage.py ,显示如下内容说明成功运行:
浏览器中输入 http://127.0.0.1:8000/, 确认链接成功
在 v3/urls.py 中添加url信息,代码如下:
from django.urls import path, include #导入include urlpatterns = [ path('admin/', admin.site.urls), # 新添加内容 path('tuling/', include('tuling.urls')), ]
拷贝v3_views/urls.py到tuling文件夹下, tuling/urls.py 添加处理代码,代码如下:
from django.contrib import admin from django.urls import path from . import views #导入视图 urlpatterns = [ path('t1/', views.t1), ]
在 tuling/views 添加处理代码,代码如下: ``` from django.shortcuts import render # 导入HttpResponse作为基本视图使用 from django.http import HttpResponse import datetime
# Create your views here. def v1(request): # 得到系统当前事件 now = datetime.datetime.now() # HttpResponse允许html代码作为返回值, html = "<html> <body> <h1> It is time {0}</h1> </body></html>".format(now) # 返回HttpResponse视图 return HttpResponse(html) ```
运行以上代码并输入相应地址(http://127.0.0.1:8000/tuling/t1/)进行检查
简单视图创建完毕,需要正确理解HttpResponse视图类和访问流程
数据流程 整个过程数据流程图大致如下:
浏览器->django:v1/urls->tuling/urls->view.t1->HttpResponse->浏览器
5.2. 其他简单视图¶
django.http给我们提供类很多和HttpResponse类似的简单视图,通过查看django.http代码我们知道, 总共django给我们定义了一下一些简单类,如下图所示:
此类视图使用方法基本类似,可以通过return语句作为反馈直接反馈返回给浏览器
Http404为Exception子类,所以需要raise使用,代码案例如下
# tuling/urls.py urlpatterns = [ path('t1/', views.t1), path('t2/', views.t2), #引发异常 ] # tuling/views.py ....... from django.http import Http404 ....... def t2(r): """ :param r: HttpRequest实例 :return: """ raise Http404("这个锅我不背,不背不背就不背")
最终结果如下图所示:
5.3. HttpRequest对象¶
HttpRequest介绍
- 服务器接收到http协议的请求后,会根据报文创建HttpRequest对象
- 视图函数的第一个参数是HttpRequest对象
- 在django.http模块中定义了HttpRequest对象的API
属性
下面除非特别说明,属性都是只读的
path:一个字符串,表示请求的页面的完整路径,不包含域名
#加入请求的是以下博客地址 http://www.mycode.wang/blog/liudana/124.html #则解析得到的request.path是: blog/liudana/124.html
method:一个字符串,表示请求使用的HTTP方法,常用值包括:’GET’、’POST’, 具体讲解会在Restfull中
encoding:一个字符串,表示提交的数据的编码方式
- 如果为None则表示使用浏览器的默认设置,一般为utf-8
- 这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值
GET:一个类似于字典的对象,包含get请求方式的所有参数
POST:一个类似于字典的对象,包含post请求方式的所有参数
FILES:一个类似于字典的对象,包含所有的上传文件
COOKIES:一个标准的Python字典,包含所有的cookie,键和值都为字符串
session:一个既可读又可写的类似于字典的对象,表示当前的会话,只有当Django 启用会话的支持时才可用,详细内容见“状态保持”
方法
- is_ajax():如果请求是通过XMLHttpRequest发起的,则返回True
QueryDict对象
- 定义在django.http.QueryDict
- request对象的属性GET、POST都是QueryDict类型的对象
- 与python字典不同,QueryDict类型的对象用来处理同一个键带有多个值的情况
- 方法get():根据键获取值
- 只能获取键的一个值
- 如果一个键同时拥有多个值,获取最后一个值
- 方法getlist():根据键获取值
- 将键的值以列表返回,可以获取一个键的多个值
GET属性
当用户发起一个http协议中的get方法请求的时候,HttpRequest.GET会被各种值填充
本质上是一个QueryDict类型的对象
它包含get请求方式的所有参数
一个常见的GET请求URL形如:
HTTP:GET : http://127.0.0.1:8080/a/b/c?id=1&k=w
请求参数是与url请求地址中的参数对应,位于?后面的形如
k=w
的键值对参数的格式是键值对,如key1=value1
多个参数之间,使用&连接,如key1=value1&key2=value2
键是开发人员定下来的,值是可变的
案例代码tuling/views/t3_get
# tuling/urls.py ... ... path('t3/', views.t3_get), ... ... # tuling/v3_views.py下代码 ... ... def t3_get(request): rst = "" for k,v in request.GET.items(): rst += k + "-->" + v rst += "," return HttpResponse("Get value of Request is {0} ".format(rst))
访问结果如图如图:
对于request.GET内容的使用,一定不能按正常字典的使用那样获取值,而应该使用 自带的get函数,确保不会出现问题,代码示例如下:
#不应该这样使用,GET是一个特殊的字典 s = r.GET["name"] #获取GET内值的方法应该是使用内置get方法 r.GET.get("name", """)
POST属性
QueryDict类型的对象
包含post请求方式的所有参数
与form表单中的控件对应
表单中空间必须有name属性,name为键,value为值
- checkbox存在一键多值的问题
键是开发人员定下来的,值是可变的
案例 tuling/views/t4_post 和 tuling/views/t4_get
因为需要用到模板,需要先设置下,后面会具体讲,settings中设置模板位置
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', #添加模板位置 'DIRS': [os.path.join(BASE_DIR, 'templates')], ... ...
设置get页面的urls和函数
# tuling/urls.py urlpatterns = [ ... ... #添加两个路由 path('t4_get/', views.t4_get), path('t4_post/', views.t4_post), ]
views中设置代码
# tuling/views.py # 在文件中添加下面两个处理函数 def t4_get(r): return render_to_response("for_post.html") def t4_post(r): rst = "" for k,v in request.POST.items(): rst += k + "-->" + v rst += "," return HttpResponse("Get value of POST is {0} ".format(rst))
添加文件和文件夹: /tuling/templates/for_post.html
由于安全原因,需要在设置中安全选项中删除csrf设置
# settings.py MIDDLEWARE = [ ... ... 'django.middleware.common.CommonMiddleware', # 下面这句话被注释掉 #'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', ... ...1`
5.4. HttpResponse详解¶
- 方法
- init :使用页内容实例化HttpResponse对象
- write(content):以文件的方式写
- flush():以文件的方式输出缓存区
- set_cookie(key, value=’’, max_age=None, expires=None):设置Cookie
- key,value都是字符串类型
- max_age是一个整数,表示在指定秒数后过期
- expires是一个datetime或timedelta对象,会话将在这个指定的日期/时间过期,注意datetime和timedelta值只有在使用PickleSerializer时才可序列化
- max_age与expires二选一
- 如果不指定过期时间,则两个星期后过期
- delete_cookie(key):删除指定的key的Cookie,如果key不存在则什么也不发生
5.5. 4. HttpResponseRedirect¶
重定向,服务器端跳转
构造函数的第一个参数用来指定重定向的地址
案例 tuling/views.py
# 在 tuling/urls中添加一下内容 urlpatterns = [ path('t1/', views.t1), path('t2/', views.t2), path('t3/', views.t3_get), path('t4_get/', views.t4_get), path('t4_post/', views.t4_post), path('t5_1/', views.t5_1), path('t5_2/', views.t5_2), path('t6/', views.t6, name="t6"), # tuling/views.py中添加以下内容 # 导入下面内容 from django.http import HttpResponse, Http404, HttpResponseRedirect from django.urls import reverse ... ... def t5_1(request): return HttpResponseRedirect("/tuling/t6") def t5_2(request): return HttpResponseRedirect(reverse("t6")) def t6(request): return HttpResponse("哈哈,这是t5的访问返回呀")
5.6. 手动编写视图¶
实验目的:
- 利用django快捷函数手动编写视图处理函数
- 编写过程中理解视图运行原理
分析:
- django把所有请求信息封装入request
- django通过urls模块把相应请求跟事件处理函数链接起来,并把request作为参数传入
- 在相应的处理函数中,我们需要完成两部分
- 处理业务
- 把结果封装并返回,我们可以使用简单HttpResponse,同样也可以自己处理此功能,例如我们本例需要做的
- 本案例不介绍业务处理,把目光集中在如何渲染结果并返回
render(request, template_name[, context][, context_instance][, content_type][, status][, current_app][, dirs][, using])
- 使用模板和一个给定的上下文环境,返回一个渲染和的HttpResponse对象
- request: django的传入请求
- template_name: 模板名称
- content_instance: 上下文环境
render_to_response(template_name[, context][, context_instance][, content_type][, status][, dirs][, using])[source]
- 根据给定的上下文字典渲染给定模板,返回渲染后的HttpResponse
- 已经不推荐
redirect(to, [permanent=False, ]*args, **kwargs)[source]¶
参数可以是:
- 使用django.url.reverse的反向解析
- 绝对或者相对URL,将原封不动的作为重定向的位置
默认返回一个临时的重定向, permanent=True时可以返回一个永久重定向
所谓重定向就是将网页自动转向重定向,即:301永久性重定向和302临时性重定向。
5.7. 系统内建视图¶
常用视图系统有内建,可以直接使用
在http.views.defaults中定义
404
- default.page_not_found(request, template_name=’404.html’)
- 系统引发Http404时出发
- 默认船体request_path变量给模板,即导致错误的URL
- DEBUG=True则不会调用404, 取而代之是调试信息
- 404视图会被传递一个RequestContext对象并且可以访问模板上下文处理器提供的变量(MEDIA_URL等)
- 参看示例代码:
500(server error)
- defaults.server_error(request, template_name=’500.html’)
- 需要DEBUG=False,否则不调用
403 (HTTP Forbidden) 视图
- defaults.permission_denied(request, template_name=’403.html’)
- 通过PermissionDenied触发
400 (bad request) 视图
- defaults.bad_request(request, template_name=’400.html’)
- DEBUG=False
示例代码
# tuling/views.py # urls也需要进行设定 from django.views import defaults ... ... def t7(r): return defaults.page_not_found(r, "找不到呀", "404.html")
5.8. 基于类的视图¶
到现在为止我们的视图都是一个一个函数,一般每个请求对应一个函数,本章开始学习利用面向对象来 编写视图。
和基于函数的视图的优势和区别:
- HTTP方法的methode可以有各自的方法,不需要使用条件分支来解决
- 可以使用OOP技术(例如Mixin)
概述
核心是允许使用不同的实例方法来响应不同的HTTP请求方法,而避开条件分支实现
as_view函数作为类的可调用入口,该方法创建一个实例并调用dispatch方法, 按照请求方法对请求进行分发,如果该 方法没有定义,则引发HttpResponseNotAllowed
参看案例1:
修改tuling/urls.py
path('t8/', views.TestView.as_view()),
修改tuling/views.py
from django.views.generic import View, TemplateView class TestView(View): def get(self, r): return HttpResponse("Hello GET") def post(self, r): return HttpResponse("Hello POST")
类属性使用 每个类都可能有相应的类属性,我们基于类的视图一般都是作为视图类的子类存在,不可避免的需要一些 类的属性,此时一般类的属性的处理有两种方法:
在类定义时直接覆盖
在调用as_view的时候直接昨晚参数使用
TemplateView案例
修改tuling/urls.py
path('t9/', views.GreetingView.as_view()),
修改tuling/views.py
class GreetingView(TemplateView): #本类需要继承模板视图,默认有一个模板支持 template_name = "for_class_view.html" #getting 在urls里面给了一个赋值 #调用post的时候明显看到getting的值发生了改变 greeting = "Say something" def post(self, r): data = dict(r.POST) print(data) print(self.greeting) return HttpResponse("Hello ")
对基于类的视图的扩充大致有三种方法:
- Mixin
- 装饰as_view
- 装饰dispatch
使用Mixin
- 多继承的一种形式,来自父类的行为和属性组合在一起
- 解决了多继承问题
- View的子类只能单继承,多继承会导致不可期问题
在urls中装饰as_view
# 此代码是django2.0 以前代码,不保证在django2上能继续运行 from django.contrib.auth.decorators import login_required, permission_required from django.views.generic import TemplateView from .views import VoteView urlpatterns = [ url(r'^about/', login_required(TemplateView.as_view(template_name="secret.html"))), url(r'^vote/', permission_required('polls.can_vote')(VoteView.as_view())), ]
装饰类的dispatch函数
类的方法和独立方法不同,不能直接运用装饰器,需要用methode_decorator进行装饰
from django.contrib.auth.decorators import login_required from django.utils.decorators import method_decorator from django.views.generic import TemplateView class ProtectedView(TemplateView): template_name = 'secret.html' @method_decorator(login_required) def dispatch(self, *args, **kwargs): return super(ProtectedView, self).dispatch(*args, **kwargs)