04 视图层
1. 视图函数
视图函数,简称视图,属于Django的视图层,默认定义在views.py文件中,是用来处理web请求信息以及返回响应信息的函数,所以研究视图函数只需熟练掌握两个对象即可:请求对象(HttpRequest)和响应对象(HttpResponse)
2. 请求对象
当一个页面被请求时,django会创建一个包含本次请求原信息(如http协议请求报文中的请求行、首部信息、内容主体)的HttpRequest对象。
之后,django会找到匹配的视图,将该对象传给视图函数的第一个参数,约定俗称该参数名为request(类似于我们自定义框架的environ参数)。
在视图函数中,通过访问该对象的属性便可以提取http协议的请求数据
2.1 request对象常用属性 1
一.HttpRequest.method
获取请求使用的方法(值为纯大写的字符串格式)。例如:"GET"、"POST"
应该通过该属性的值来判断请求方法
在视图函数中:
if request.method. == "GET":
...
if request.method == "POST":
...
'''
request.mothod 请求方式
request.POST POST请求
request.GET GET请求
request.FILES 获取前端传的文件格式
request.path 获取路径
request.path_info
request.get_full_path() 能获取完整的url及问号后面的参数
request.body # 原生的浏览器发过来的二进制数据
'''
print(request.path) # /app01/ab_file
print(request.path_info) # /app01/ab_file/
print(request.get_full_path()) # /app01/ab_file/?username=wyz
2.2 request对象常用属性 2
1.1 当浏览器基于http协议的GET方法提交数据时,数据会按照k1=v1&k2&v2的格式放到url中,然后发送给django,django会将这些数据封装到request.GET中,
1.2 当浏览器基于http协议的POST方法提交数据时数据会被放到请求体中发送给django,django会将接收到的请求体数据存放于HttpRequest.body属性中,但该属性的值为Bytes类型(套接字数据传输都是bytes类型),而通常情况下直接处理Bytes,并从中提取有用数据的操作是复杂而繁琐的,好在django会对它做进一步的处理与封装以便我们更为方便地提取数据,具体如何处理呢?
当前端采用POST提交数据时,数据有三种常用编码格式,编码格式不同Django会有不同的处理方式
# 编码格式一 urlencode,是form表单默认编码格式(request.post 获取数据)
# 编码格式二 form-data 上传文件专用格式(request.FILES获取数据)
# 编码格式三 json 提交json格式字符串(request.post)
1.3 如何设定POST提交数据的编码格式
前端往后台POST提交数据,常用技术有form表单和ajax两种
form表单可以设置的数据编码格式有:编码格式1、编码格式2
ajax可以设置的数据编码格式有:编码格式1、编码格式2、编码格式3
2.4、HttpRequest对象常用属性3(暂作了解)
"""
django将请求报文中的请求行、头部信息、内容主体封装成 HttpRequest 类中的属性。
除了特殊说明的之外,其他均为只读的。
"""
一.HttpRequest.META
值为包含了HTTP协议的请求头数据的Python字典,字典中的key及期对应值的解释如下
CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
CONTENT_TYPE —— 请求的正文的MIME类型。
HTTP_ACCEPT —— 响应可接收的Content-Type。
HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
HTTP_HOST —— 客服端发送数据的目标主机与端口
HTTP_REFERER —— Referring 页面。
HTTP_USER_AGENT —— 客户端使用的软件版本信息
QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
REMOTE_ADDR —— 客户端的IP地址。
REMOTE_HOST —— 客户端的主机名。
REMOTE_USER —— 服务器认证后的用户。
REQUEST_METHOD —— 一个字符串,例如"GET" 或"POST"。
SERVER_NAME —— 服务器的主机名。
SERVER_PORT —— 服务器的端口(是一个字符串)。
从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,HTTP协议的请求头数据转换为 META 的键时,
都会
1、将所有字母大写
2、将单词的连接符替换为下划线
3、加上前缀HTTP_。
所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。
注意:下述常用属性暂且了解即可,待我们讲到专门的知识点时再专门详细讲解
二.HttpRequest.COOKIES
一个标准的Python 字典,包含所有的cookie。键和值都为字符串。
三.HttpRequest.session
一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django 启用会话的支持时才可用。
11.HttpRequest.user(用户认证组件下使用)
一个 AUTH_USER_MODEL 类型的对象,表示当前登录的用户。
2.HttpRequest.is_ajax()
如果请求是通过XMLHttpRequest 发起的,则返回True,方法是检查 HTTP_X_REQUESTED_WITH 相应的首部是否是字符串'XMLHttpRequest'。
大部分现代的 JavaScript 库都会发送这个头部。如果你编写自己的 XMLHttpRequest 调用(在浏览器端),你必须手工设置这个值来让 is_ajax() 可以工作。
如果一个响应需要根据请求是否是通过AJAX 发起的,并且你正在使用某种形式的缓存例如Django 的 cache middleware,
你应该使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 装饰你的视图以让响应能够正确地缓存。
四.HttpRequest.encoding
一个字符串,表示提交的数据的编码方式(如果为 None 则表示使用 DEFAULT_CHARSET 的设置,默认为 'utf-8')。
这个属性是可写的,你可以修改它来修改访问表单数据使用的编码。
接下来对属性的任何访问(例如从 GET 或 POST 中读取数据)将使用新的 encoding 值。
如果你知道表单数据的编码不是 DEFAULT_CHARSET ,则使用它。
五.HttpRequest.scheme
表示请求方案的字符串(通常为http或https)
六.HttpRequest.user
一个AUTH_USER_MODEL类型的对象,表示当前登录的用户。
如果用户当前没有登录,user将设置为django.contrib.auth.models.AnonymousUser的一个实例。
你可以通过is_authenticated()区分它们,例如:
if request.user.is_authenticated():
# Do something for logged-in users.
else:
# Do something for anonymous users.
HttpRequest.user只有当Django 启用 AuthenticationMiddleware中间件时才可用。
匿名用户
class models.AnonymousUser
django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,但具有下面几个不同点:
id 永远为None。
username 永远为空字符串。
get_username() 永远返回空字符串。
is_staff 和 is_superuser 永远为False。
is_active 永远为 False。
groups 和 user_permissions 永远为空。
is_anonymous() 返回True 而不是False。
is_authenticated() 返回False 而不是True。
set_password()、check_password()、save() 和delete() 引发 NotImplementedError。
New in Django 1.8:
新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。
3.三板斧
3.1、HttpResponse
传递字符串
from django.http import HttpResponse
response = HttpResponse("Here's the text of the Web page.")
response = HttpResponse("Text only, please.", content_type="text/plain")
'''
ps:Content-Type用于指定响应体的MIME类型
MIME类型:
mime类型是多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开
MIME 类型有非常多种,一般常见的有:
text/html:浏览器在获取到这种文件时会自动调用html的解析器对文件进行相应的处理。
text/plain:意思是将文件设置为纯文本的形式,浏览器在获取到这种文件时并不会对其进行处理。
image/jpeg:JPEG格式的图片
image/gif:GIF格式的图片
video/quicktime:Apple 的 QuickTime 电影
application/vnd.ms-powerpoint:微软的powerpoint文件
'''
3.2、render
def render(request, template_name, context=None, content_type=None, status=None, using=None):
"""
Return a HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
"""
content = loader.render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)
参数:
1、request:用于生成响应的请求对象,固定必须传入的第一个参数
2、template_name:要使用的模板的完整名称,必须传入,render默认会去templates目录下查找模板文件
3、context:可选参数,可以传入一个字典用来替换模块文件中的变量,默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。
4、content_type:生成的文档要使用的MIME类型。默认为 DEFAULT_CONTENT_TYPE 设置的值。默认为'text/html'
5、status:响应的状态码。默认为200。
6、useing: 用于加载模板的模板引擎的名称。
综上,render的功能可以总结为:根据给定字典渲染模板文件,并返回一个渲染后的HttpResponse对象。
3.3、redirect
返回重定向对象,返回的状态码为302,第一个参数用来指定浏览器重定向的地址,可以是
#1、一个完全标准的URL地址,如'https://www.yahoo.com/search/'
#2、也可以是一个没有域名的绝对路径,如'/search/'
#3、或者是一个没有域名的相对路径,如'search/',与1、2直接跳转到指定的绝对路径不同,相对路径需要先与当前路径进行拼后才能跳转,例如:如果当前路径为http://127.0.0.1:8080/index/,拼接后的路径为http://127.0.0.1:8080/index/search/
# ps:redirect重定向等同于下述操作
def index(request):
response=HttpResponse()
response.status_code=302 # 必须设置响应的状态码,才能重定向
response['Location']='/register/' # 设置响应头
return response
4. JsonResponse对象
向前端返回一个json格式字符串的两种方式
方式一:
import json
def my_view(request):
data=['egon','kevin']
return HttpResponse(json.dumps(data) )
方式二:
from django.http import JsonResponse
# Create your views here.
def ad_json(request):
user_dic = {'username': 'wyz真帅,雀食蟀'}
l = [11, 22, 22]
return JsonResponse(user_dic, json_dumps_params={'ensure_ascii': False})
# JsonResponse默认不能转化列表,将safe设置成False即可
return JsonResponse(l, safe=False)
5. form表单上传文件及后端如何操作
'''
form表单上传文件类型的数据
1.method必须指定成post
2.enctype必须换成formdata
'''
后端中
def formh(request):
if request.method == 'POST':
# print(request.POST) # 只能获取普通的简直对数据 文件不行
print(request.FILES) # <MultiValueDict: {'file': [<InMemoryUploadedFile: 1.png (image/png)>]}>
return render(request, 'formH.html')
6. FBV与CBV
# 视图函数既可以是函数也可以是类
def index(request):
return HttpResponse('index')
# CBV
# CBV路由
url(r'^login/',views.MyLogin.as_view())
'''
FBV和CBV各有千秋
CBV特点
能够直接根据请求方式的不同直接匹配到对应的方法执行
内部到底是怎么实现的?
CBV内部源码
'''
7. 分析CBV源码代码
小提示:看python源码时,一定要时刻提醒自己面向对象属性方法查找顺序,
先从自己对象找,再去产生对象的类里面找,之后去父类去找
总结:看源码只要看到了self点一个东西,就一定要搞清楚这个self到底是谁
# 突破口在urls.py
url(r'^login/', views.Mylogin.as_view()),
# 上述代码再启动django的时候就会立刻执行as_view方法
# url(r'^login/', views.view) 和 FBV一模一样
# CBV和FBV在路由匹配本质上是一样的
函数/方法 加括号执行优先级最高
as_view()
是被@classmethod修饰的类方法
@classonlymethod
def as_view(cls, **initkwargs):
pass
# 源码 精简版
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
self = cls(**initkwargs)
# self = cls(**initkwargs) 相当于Mylogin(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
return self.dispatch(request, *args, **kwargs)
return view
def dispatch(self, request, *args, **kwargs):
# 获取当前请求方式的小写格式,然后比对当前请求方式是否合法
# 以get请求为例
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
# 反射getattr方法,self是自己写的类实例的对象,get方法找得到,获得get方法,找不到就会用到第三个参数(报错)
# handler = 我们自己写的类(Mylogin)里面的get方法
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
# 自动调用get方法