Django框架之视图层

一、视图函数

视图函数,简称视图,属于Django的视图层,默认定义在views.py文件中。

是用来处理web请求信息以及返回响应信息的函数,所以研究视图函数只需要掌握两个对象即可。

请求对象(HttpRequest)

响应对象(HttpResponse)

二、请求对象(HttpRequest)

Django将http协议请求数据报中的请求头、请求首行、 、请求内容主体封装到了HttpRequest对象中(类似于我们自定义web框架的env参数)。

Django会将HttpRequest 对象当作参数传给视图函数的第一个参数request,在视图函数中,通过访问该对象的属性便可以提取http协议的请求数据

2.1 请求对象的常用属性

一、HttpRequest.method
	获取浏览器访问服务器的请求方式(GET/POST)
    注意:值为纯大写的字符串格式 'GET' 'POST'
    作用:通过该属性的值来判断浏览器对服务器的请求方式
    
二、HttpRequest.GET
	值为一个类似于字典的QueryDict对象,封装了GET请求的所有参数
    可通过HttpRequest.GET.get('请求到后端的键值(key)') 获取相应的值value
    
三、HttpRequest.POST
	(这个一般用于表单中)
	值为一个类似于字典的QueryDict对象,封装了GET请求的所有参数
    可通过HttpRequest.POST.get('请求到后端的键值(key)') 获取相应的值value

三、HttpResponse(响应对象)

响应对象是服务器返回给浏览器的信息,响应信息可以是任何形式的内容。

比如一个Html页面的内容,一个重定向的内容(可以是第三方的),一个404错误、一个xml文档,或者是一张图片等。总之,无论视图本身包含什么逻辑,都要返回响应,具体的说,响应对象主要有三种形式

记住:django所有的响应信息的方式,他们都是属于一个HttpResponse对象

# HttpResponse对象的三种形式
from django.shortcuts import render # 返回html页面
from django.shortcuts import HttpResponse # 返回一个字符串,
from django.shortcuts import redirect # 重定向

3.1 HttpResponse() 响应字符串

括号内直接写一个具体的字符串作为响应体,比较直接简单,所以这里主要介绍后面两种形式

3.2 render() 响应html页面

render(request,templates_name[,context])

参数:

  1. request:用于生成响应的请求对象,固定必须传入的第一个参数
  2. templates_name: 要使用的模板的完整名称,必须传入,render默认去templates文件夹下找这个html页面(模板文件)
  3. context:可选的参数,可以传入一个字典用来代替模块文件中的变量

总结:render的功能可以总结为:根据给定字典渲染模板文件,并返回渲染后的HttpResponse对象

3.3 redirect() 重定向

# 返回重定向信息
def index(request):
    return redirect('login/')

# 重定向的地址也可以是一个完整的url
def index(request):
    return redirect('http://www.baidu.com/')

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

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

四、JsonResponse(返回json字符串)

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

方式一:通过json模块

import json
def my_view(request):
    data = ['cecilia','xichen']
    return HttpResponse(json.dumps(data))

方式二:通过JsonResponse对象

JsonResponse对象默认只能序列化字典,想要序列化别的类型必须将safe=False

另外:如果想显示中文,必须

from django.http import JsonResponse

def my_view(request):
    data = ['cecilia','xichen']
    return JsonResponse(data,safe=False)
# 默认safe=True代表只能序列化字典对象,safe=False代表可以序列化字典以外的对象

4.1 补充小例子:如何手动实现python中Json任意格式徐磊话

json.JSONEncoder:可以看到json模块支持哪些类型序列化

  1. 写一个类继承 json.JSONEncoder,重写default方法,返回json能够转的类型
  2. 序列化,指定类,并指定不用ASCII码进行解析
import json,datetime

class MyJson(json.JSONEncoder):
    def default(self, o):
        if isinstance(o,datetime.datetime):
            return o.strftime('%Y-%m-%d %X')
        else:
            return super().default(o)
        
d = datetime.datetime.now()
# 序列化日期对象,指定类,指定支持中文
json_str = json.dumps(d,cls=MyJson,ensure_ascii=False)
print(json_str,type(json_str))

五、form表单上传文件

注意事项:

  1. 提交方式必须是post
  2. enctype参数必须有默认的urlencoded变成formdata
  3. request.FILES 获取文件对象

5.1 上传文件的两种方式

'''表单上传文件'''
def upload(request):
    if request.method == "POST":
        print(request.POST)
        
        '''上传文件的两种方式'''
        # 方式1:得到文件对象,然后循环文件句柄,写入
        file_obj = request.FILES.get("myfile")
        with open(file_obj.name,'wb') as f:
            for line in file_obj:
                f.write(line)

        # 方式2:得到文件对象,然后循环 文件对象.chunks(),写入
        # with open(file_obj.name, 'wb') as f:
        #     for line in file_obj.chunks():
        #         f.write(line)

    return render(request,"upload.html")

六、FBV和CBV

django的视图层由两种形式构成:FBV和CBV

  1. FBV基于函数的视图(function base view):我们之前一直介绍的都是FBV
  2. CBV基于类的视图(class base view): 通过自定义类继承View类实现get和post方法

6.1 实现CBV的方法

  1. 先在视图层中:自定义类继承自View类,重写get和post方法
  2. 先在路由层中:添加路由与视图函数对应关系
# views.py视图文件
from django.views import View
class loginview(View):
    def dispatch(self,request,*args,**kwargs): # 可在该方法内做一些预处理操作
        
        # 当请求url:http://127.0.0.1:8001/login/会触发dispatch的执行
        # 如果http协议的请求方法为GET,则调用下述get方法
        # 如果http协议的请求方法为POST,则调用下述post方法
        obj = super().dispatch(request,*args,**kwargs)# 必须继承父类的dispatch功能
        return obj # 必须返回obj

    def get(self,request):
        return render(request,'login.html')

    def post(self,request):
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')
        if name == 'cecilia' and pwd == '123':
            res = '登录成功'
        else:
            res = '用户密码错误'
        return HttpResponse(res)
# urls.py路由文件
from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    
    # 测试CBV下的视图
    url(r'^login/',views.loginview.as_view()),# 当 as_view()被执行后的结果就是一个闭包函数。
    
]

6.2 分析CBV的执行流程

为什么前端get请求来就会触发get方法?

  1. 首先,在路由层中写了 url(r'^login/',views.loginview.as_view()),这句话会当项目启动后自动让as_view()去执行。
  2. 它执行后的结果会得到一个闭包函数对象。那么此时路由层中的url就变成了url(r'^login/', views.view),此时在路由配置上,已经和其他一样,都是内存地址
  3. 当浏览器访问时,成功匹配该url就会调用该闭包函数。
  4. 执行闭包函数,先是实例化得到了自己自定义类的对象,并添加了属性。然后执行了对象的dispatch方法
  5. dispatch方法内,判断了请求类型是否符合要求,然后通过反射得到自定义类中的函数,最后调用该函数。
原文地址:https://www.cnblogs.com/XuChengNotes/p/11735730.html