博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
django判断checkbox是否选中_django视图层之请求与响应
阅读量:6269 次
发布时间:2019-06-22

本文共 15607 字,大约阅读时间需要 52 分钟。

01 Django视图层-请求与响应

一 视图函数

视图函数,简称视图,属于Django的视图层,默认定义在views.py文件中,是用来处理web请求信息以及返回响应信息的函数,所以研究视图函数只需熟练掌握两个对象即可:请求对象(HttpRequest)和响应对象(HttpResponse)

官网地址:https://docs.djangoproject.com/en/1.11/ref/request-response/

d231b82b1ef68cd047d51be935af4be1.png

二 请求对象

​ 当一个页面被请求时,django会创建一个包含本次请求原信息(如http协议请求报文中的请求行、首部信息、内容主体)的HttpRequest对象。

​ 之后,django会找到匹配的视图,将该对象传给视图函数的第一个参数,约定俗称该参数名为request(类似于我们自定义框架的environ参数)。

​ 在视图函数中,通过访问该对象的属性便可以提取http协议的请求数据

2.1、HttpRequest对象常用属性part1

一.HttpRequest.method  获取请求使用的方法(值为纯大写的字符串格式)。例如:"GET"、"POST"   应该通过该属性的值来判断请求方法   在视图函数中:   if request.method. == "GET":       ...   if request.method == "POST":       ...二.HttpRequest.GET  值为一个类似于字典的QueryDict对象,封装了GET请求的所有参数,可通过HttpRequest.GET.get('键')获取相对应的值   在视图函数中:   request.GET.get('name')三.HttpRequest.POST   值为一个类似于字典的QueryDict对象,封装了POST请求所包含的表单数据,可通过HttpRequest.POST.get('键')获取相对应的值   在视图函数中:   request.POST.get('name')   针对表单中checkbox类型的input标签、select标签提交的数据,键对应的值为多个,需要用:HttpRequest.POST.getlist("hobbies")获取存有多个值的列表,同理也有HttpRequest.GET.getlist("键")   针对有多个值的的情况,也可以用HttpRequest.GET.get("键"),会获取列表中的最后一个值

案例:

urls.py

from django.urls import re_pathfrom app01 import viewsurlpatterns = [    re_path(r'^login/$',views.login),]

Views.py

from django.shortcuts import render,HttpResponsedef login(request):    if request.method == 'GET':        # 当请求url为:http://127.0.0.1:8001/login/?a=1&b=2&c=3&c=4&c=5        # 请求方法是GET,?后的请求参数都存放于request.GET中        print(request.GET)        # 输出
# 获取?后参数的方式为 a=request.GET.get('a') # 1 b=request.GET.get('b') # 2 c=request.GET.getlist('c') # ['3', '4', '5'] c1=request.GET.get('c') # 5 return render(request,'login.html') elif request.method == 'POST': # 在输入框内输入用户名egon、年龄18,选择爱好,点击提交 # 请求方法为POST,表单内的数据都会存放于request.POST中 print(request.POST) # 输出
# 获取表单中数据的方式为 name=request.POST.get('name') # egon age=request.POST.get('age') # 18 hobbies=request.POST.getlist('hobbies') # ['music', 'read'] return HttpResponse('提交成功')

在templates目录下新建login.html

    
登录页面
{% csrf_token %}

用户名:

年龄:

爱好: 音乐 阅读 跳舞

2.2、HttpRequest对象常用属性part2(重点)

一.HttpRequest.body  1.1 当浏览器基于http协议的GET方法提交数据时(没有请求体一说),数据会按照k1=v1&k2=v2&k3=v3的格式放到url中,然后发送给django,django会将这些数据封装到request.GET中,注意此时的请求体request.body为空、无用  1.2 当浏览器基于http协议的POST方法提交数据时,数据会被放到请求体中发送给django,django会将接收到的请求体数据存放于HttpRequest.body属性中.  但该属性的值为Bytes类型(套接字数据传输都是bytes类型),而通常情况下直接处理Bytes、并从中提取有用数据的操作是复杂而繁琐的,好在django会对它做进一步的处理与封装以便我们更为方便地提取数据,具体如何处理呢?  当前端采用POST提交数据时,数据有三种常用编码格式,编码格式不同Django会有不同的处理方式  # 编码格式1:application/x-www-form-urlencoded,是form表单默认编码格式  # 编码格式2:multipart/form-data,上传文件专用格式  # 编码格式2:application/json,提交jason格式字符串  #====》I: 当POST数据的编码格式为application/x-www-form-urlencoded时《====      HttpRequest.body中的数据格式为b'a=1&b=2&c=3'      django会将其提取出来封装到request.POST中      request.FILES此时为空      如:      print(request.body) # b'a=1&b=2&c=3'      print(request.POST) # 
#====》II: 当POST数据的编码格式为multipart/form-data时《==== 详见:https://my.oschina.net/cnlw/blog/168466?fromerr=aQL9sTI2 HttpRequest.body中的数据格式为b'------WebKitFormBoundaryKtcwuksQltpNpreprnContent-Disposition: form-data;......',注意,文件部分数据是流数据,所以不在浏览器中显示是正常的 django会将request.body中的非文件数据部分提取出来封装到request.POST中 将上传的文件部分数据专门提取出来封装到request.FILES属性中 如: print(request.body) # 不要打印它,打印则报错,因为它是数据流 print(request.POST) #
]}> 强调: 1、毫无疑问,编码格式2的数据量要大于编码格式1,如果无需上传文件,还是推荐使用更为精简的编码格式1 2、FILES will only contain data if the request method was POST and the
that posted to the request had enctype="multipart/form-data". Otherwise, FILES will be a blank dictionary-like object. #===》III: 当POST数据的编码格式为application/json时《==== 此时在django后台,request.POST和request.FILES中是没有值的,都放到request.body中了,需要用json.loads对其进行反序列化 如: print(request.body) # b'{"a":1,"b":2,"c":3}' print(request.POST) #
print(request.FILES) #
1.3 如何设定POST提交数据的编码格式 前端往后台POST提交数据,常用技术有form表单和ajax两种 form表单可以设置的数据编码格式有:编码格式1、编码格式2 ajax可以设置的数据编码格式有:编码格式1、编码格式2、编码格式3 我们将在后续章节中介绍ajax技术,此处我们先介绍我们熟知的form表单 form表单可以通过属性enctype进行设置编码格,如下 编码格式1(默认的编码格式):enctype="application/x-www-form-urlencoded" 编码格式2(使用form表单上传文件时只能用该编码):enctype="multipart/form-data"

4921754838c89ad36d5aadcd25da1677.png

案例:form表单上传文件

urls.py

from django.urls import re_pathfrom app01 import viewsurlpatterns = [    re_path(r'^register/$',views.register),]

views.py

from django.shortcuts import render,HttpResponsedef register(request):    '''    保存上传文件前,数据需要存放在某个位置。默认当上传文件小于2.5M时,django会将上传文件的全部内容读进内存。从内存读取一次,写磁盘一次。    但当上传文件很大时,django会把上传文件写到临时文件中,然后存放到系统临时文件夹中。    '''    if request.method == 'GET':        return render(request, 'register.html')    elif request.method == 'POST':        # print(request.body) # 读取流数据会抛出异常,请注释掉它        # 从request.POST中获取用户名        name = request.POST.get('name')        # 从request.FILES获取文件对象        file_obj = request.FILES.get('header_img')        # 从文件对象中获取文件名        filename = file_obj.name        print(filename)        file_obj.chunks()        # 上传的文件存放于templates文件夹下        with open('templates/%s' %filename, 'wb') as f:            for line in file_obj.chunks():                f.write(line)        return HttpResponse('注册成功')    # 强调:    '''    file_obj.read() 当文件过大时,会导致内存溢出,系统崩溃    应该使用file_obj.chunks()读取,官网解释如下    uploadedFile.chunks(chunk_size=None)¶    A generator returning chunks of the file. If multiple_chunks() is True, you should use this method in a loop instead of read().    In practice, it’s often easiest simply to use chunks() all the time. Looping over chunks() instead of using read() ensures that large files don’t overwhelm your system’s memory.    注意:直接for循环file_obj也不行,因为直接for读取文件是按照行分隔符来依次读取的,不同平台下的文件行分隔符不同,有可能一行的数据就很大,所以还是推荐file_obj.chunks()来读取,官网解释如下    Like regular Python files, you can read the file line-by-line simply by iterating over the uploaded file:    for line in uploadedfile:        do_something_with(line)    Lines are split using universal newlines. The following are recognized as ending a line: the Unix end-of-line convention 'n', the Windows convention 'rn', and the old Macintosh convention 'r'.    '''

在templates目录下新建register.html

    
注册页面
{
% csrf_token %}

用户名:

头像:

2.3、HttpRequest对象常用属性part3

一.HttpRequest.path  获取url地址的路径部分,只包含路径部分二.HttpRequest.get_full_path()  获取url地址的完整path,既包含路径又包含参数部分如果请求地址是http://127.0.0.1:8001/order/?name=egon&age=10#_label3,HttpRequest.path的值为"/order/"HttpRequest.get_full_path()的值为"/order/?name=egon&age=10"

案例:

urls.py

from django.urls import path,register_converter,re_pathfrom app01 import viewsurlpatterns = [    re_path(r'^order',views.order),]

views.py

from django.shortcuts import render,HttpResponse# 针对请求的url地址:http://127.0.0.1:8001/order/?name=egon&age=10#_label3# 从域名后的最后一个“/”开始到“?”为止是路径部分,即/order/# 从“?”开始到“#”为止之间的部分为参数部分,即name=egon&age=10def order(request):    print(request.path) # 结果为“/order/”    print(request.get_full_path()) # 结果为"/order/?name=egon&age=10"    return HttpResponse('order page')

2.4、HttpRequest对象常用属性part4(暂作了解)

dc407973b3d1a281d7542af9de583381.png
"""  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。

插图:恶搞图03

1b1eb63e61df7cbaca1232ce169c1426.png

三 响应对象

请求对象HttpRequest是由django为我们创建好的,直接使用即可,而响应对象则需要我们负责创建。我们编写的每个视图都应该返回一个HttpResponse对象,响应可以是一个网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。用来返回响应对象的常用类如下

from django.shortcuts import HttpResponsefrom django.shortcuts import redirectfrom django.shortcuts import renderfrom django.http importJsonResponse

3.1、HttpResponse

传递字符串

from django.http import HttpResponseresponse = 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文件'''

依次增加字符串(了解)

>>> response = HttpResponse()>>> response.write("

Here's the text of the Web page.

")>>> response.write("

Here's another paragraph.

")

传递迭代器对象(了解)

# 可以为HttpResponse传递可迭代对象,HttpRespone会将其依次迭代然后存储成字符串,类似文件或者其他带有close()方法的生成器对象,会自动调用close()关闭def index(request):    f=open(r'a.txt',mode='r',encoding='utf-8') # a.txt文件内容为111    response=HttpResponse(f)    print(response.content) # 打印内容为: b'111'    # f.read() # 如果执行,则会抛出异常,说明文件已经关闭了,无法读取return response

设置或删除响应头信息

response = HttpResponse()response['Content-Type'] = 'text/html; charset=UTF-8'response['X-Frame-Options'] = 'SAMEORIGIN'del response['Content-Type']

属性

HttpResponse.status_code:响应的状态码HttpResponse.charset:响应内容的编码encode格式HttpResponse.content:响应内容

字符串编码:

# 编码设定原则:编码格式与解码格式保持一致response = HttpResponse(charset='gbk',content_type='text/html; charset=gbk')# 参数charset='gbk'指定响应体内容response.content的编码格式# 参数content_type='text/html; charset=gbk'是设置响应头,用于告诉浏览器响应体内容response.content应该采用何种解码格式,注意:设置时必须加上内容的类型,如text/html# 强调:# 如果在实例化HttpResponse时没有指定charset=gbk',将会采用与content_type中设定的解码格式一样的编码,这样统一起来就不会出现乱码问题# 如果也没有指定content_type,那么django默认会读取配置文件中的配置settings.py.DEFAULT_CHARSET来作为默认的编码与解码格式def index(request):    response = HttpResponse(charset='gbk',content_type='text/html; charset=gbk')    response.charset='gbk' # 实例化后,可以对该属性重新赋值,只要是在write内容前,就会以最新赋值的编码格式为准    response.write("

Hello egon美男子

") response.write("

Hello 林sb

") # 如果实例化处未指定响应头Content-Type,也可以在此处设置,在一处就可以了,无需重复设置 response['Content-Type']='text/html; charset=gbk' # response['Content-Type']='text/html; charset=UTF-8' print(response.charset) print(response.content) return response

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对象。简单示例如下

urls.py新增路由

from django.urls import re_pathfrom app01 import viewsurlpatterns = [    re_path(r'^$',views.index),]

views.py内容如下

from django.shortcuts import renderdef index(request):    return render(request, 'index.html', {
'name': 'egon', 'tag': 'dsb'})# 上述代码等同于from django.shortcuts import renderfrom django.template import loaderdef index(request): t = loader.get_template('index.html') dic = {
'name': 'egon', 'tag': 'dsb'} return HttpResponse(t.render(dic, request))

templates目录下新增文件index.html,内容如下

    
Title

{

{ name }}

{

{ tag }}

测试

#启动django,在浏览器中访问url地址http://ip地址:端口号/,会看到{
{ name }} {
{ tag }}被替换成了egon和dsb

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

示例如下

urls.py新增路由

from django.urls import re_pathfrom app01 import viewsurlpatterns = [    re_path(r'^index/$',views.index),    re_path(r'^login/$', views.login),]

views.py内容如下

from django.shortcuts import HttpResponse,redirectdef index(request):    return redirect('/login/') # 跳转到http://127.0.0.1:8000/login/    # return redirect('login/') # 跳转到http://127.0.0.1:8000/index/login/def login(request):    return HttpResponse("login page")

测试:

启动django,在浏览器中访问url地址http://ip地址:端口号/index/,跳转到login页面

356f1c8329374bbb300d722de3c76d72.png

重定向转态码301与302的区别(了解)

一、301和302的异同。   1、相同之处:   301和302状态码都表示重定向,具体点说就是浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址(浏览器会从响应头Location中获取新地址),用户看到的效果都是输入地址A后瞬间跳转到了另一个地址B   2、不同之处:  301表示永久重定向,旧地址A的资源已经被永久地移除了,即这个资源不可访问了。  302表示临时重定向,旧地址A的资源还在,即这个资源仍然可以访问。    A页面临时重定向到B页面,那搜索引擎收录的就是A页面。    A页面永久重定向到B页面,那搜索引擎收录的就是B页面。    从SEO层面考虑,302要好于301二、重定向原因:   1、网站调整(如改变网页目录结构);   2、网页被移到一个新地址;   3、网页扩展名改变(如应用需要把.php改成.Html或.shtml)。      这种情况下,如果不做重定向,则用户收藏夹或搜索引擎数据库中旧地址只能让访问客户得到一个404页面错误信息,访问流量白白丧失;再者某些注册了多个域名的网站,也需要通过重定向让访问这些域名的用户自动跳转到主站点等。

6d11573a2431c369ccec8d4b176a1d29.png

3.4、JsonResponse

向前端返回一个json格式字符串的两种方式

方式一:

import jsondef my_view(request):    data=['egon','kevin']    return HttpResponse(json.dumps(data) )

方式二:

from django.http import JsonResponsedef my_view(request):    data=['egon','kevin']    return JsonResponse(data,safe=False)    #默认safe=True代表只能序列化字典对象,safe=False代表可以序列化字典以外的对象

转载地址:http://vvspa.baihongyu.com/

你可能感兴趣的文章
[Javascript] Compose multiple functions for new behavior in JavaScript
查看>>
ASP.NET MVC性能优化(实际项目中)
查看>>
ES6里关于类的拓展(一)
查看>>
零元学Expression Blend 4 - Chapter 46 三分钟快速充电-设定Margin的小撇步
查看>>
Format Conditions按条件显示表格记录
查看>>
RichTextBox指定全部文字显示不同颜色及部分文字高亮颜色显示
查看>>
mysql优化----explain的列分析
查看>>
Python正则表达式
查看>>
Java中CAS详解
查看>>
Spring Boot Unregistering JMX-exposed beans on shutdown
查看>>
命令行man的帮助手册
查看>>
Ubuntu 16.04下为Android编译OpenCV 3.2.0 Manager
查看>>
poi 导入导出的api说明(大全)
查看>>
Fix-Mapped Addresses
查看>>
fmt标签如何计算两个日期之间相隔的天数
查看>>
Spark核心技术原理透视一(Spark运行原理)
查看>>
《Gradle权威指南》--Gradle任务
查看>>
IntelliJ IDEA创建文件时自动填入作者时间 定制格式
查看>>
Android app启动activity并调用onCreate()方法时都默默地干了什么?
查看>>
远程监视jboss应用java内存的配置
查看>>