# 视图概述 - 视图即视图模块,接收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) ... ... ## 简单视图 - 目的: - 创建一个简单视图函数 - 返回一段html代码 - 利用django.http包中的HttpResponse类 - 分析: - HttpResponse是一个由django提供的视图类,可以用来返回简单视图 - HttpRequest尽可能不让程序员改动内容,HttpResponse则需要手动改动内容 - 为了代码简洁,从新创建v3_views项目,添加tuling应用 - 操作步骤: 1. 启动虚拟环境 > source activate tuling_django 2. 创建项目和app >django-admin startproject v3_views >cd v3_views >python manage.py startapp tuling 3. 修改配置文件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 ] 4. 配置pycharm让软件能直接运行manage.py函数, 具体配置参看第一张django概述 5. 运行 east/manage.py ,显示如下内容说明成功运行: 6. 浏览器中输入 http://127.0.0.1:8000/, 确认链接成功 7. 在 v3/urls.py 中添加url信息,代码如下: from django.urls import path, include #导入include urlpatterns = [ path('admin/', admin.site.urls), # 新添加内容 path('tuling/', include('tuling.urls')), ] 8. 拷贝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), ] 9. 在 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 = "

It is time {0}

".format(now) # 返回HttpResponse视图 return HttpResponse(html) ``` 9. 运行以上代码并输入相应地址(http://127.0.0.1:8000/tuling/t1/)进行检查 10. 简单视图创建完毕,需要正确理解HttpResponse视图类和访问流程 - 数据流程 整个过程数据流程图大致如下: 浏览器->django:v1/urls->tuling/urls->view.t1->HttpResponse->浏览器 ## 其他简单视图 - django.http给我们提供类很多和HttpResponse类似的简单视图,通过查看django.http代码我们知道, 总共django给我们定义了一下一些简单类,如下图所示: ![其他返回实例](imgs/05.png) - 此类视图使用方法基本类似,可以通过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("这个锅我不背,不背不背就不背") 最终结果如下图所示: ![其他返回实例](imgs/05.png) ## 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)) - 访问结果如图如图: ![访问结果和访问地址](imgs/v02.png) - 对于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` ## 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不存在则什么也不发生 ## 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的访问返回呀") ## 手动编写视图 - 实验目的: - 利用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]¶ - 参数可以是: 1. 使用django.url.reverse的反向解析 2. 绝对或者相对URL,将原封不动的作为重定向的位置 - 默认返回一个临时的重定向, permanent=True时可以返回一个永久重定向 ``` 所谓重定向就是将网页自动转向重定向,即:301永久性重定向和302临时性重定向。 ``` ## 系统内建视图 - 常用视图系统有内建,可以直接使用 - 在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") ## 基于类的视图 到现在为止我们的视图都是一个一个函数,一般每个请求对应一个函数,本章开始学习利用面向对象来 编写视图。 - 和基于函数的视图的优势和区别: - 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) ```