Django之深入了解视图层

视图层三板斧

规定视图函数必须有一个返回值,

并且返回值的数据类型必须是 HttpResponse 对象

HttpResponse

返回浏览器一个字符串

render

结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。

redirect

默认返回一个临时的重定向;传递permanent=True 可以返回一个永久的重定向。

扩展阅读:

临时重定向(响应状态码:302)和永久重定向(响应状态码:301)对普通用户来说是没什么区别的,它主要面向的是搜索引擎的机器人。

A页面临时重定向到B页面,那搜索引擎收录的就是A页面。

A页面永久重定向到B页面,那搜索引擎收录的就是B页面。

JsonResponse

前提知识点:前后端数据要交互,通常情况下采用json的字符串,后端需要写好响应的url接口并返回json格式的字符串,前端在访问你这个接口就行了。

前后端json 序列化和反序列化的方法

方法 后端 前端
序列化 json.dumps JSON.stringfy
反序列化 json.loads JSON.parse

django非常友好,帮我们想到了这个问题,就有现成的对象来自动转成json的对象---JsonResponse

# 导入JsonResponse 对象
from django.http import JsonResponse
def index(request):
    user_dict = {'username':'qinyj','age':18,'hobby':'独角兽的好事'}
    # json数据序列化的时候,如果这个字典里有中文,
    # 那么序列化的时候就不能序列化中文了,需要加参数ensure_ascii=False
    return HttpResponse(json.dumps(user_dict,ensure_ascii=False))
    
    # 同样django帮你想到了这点,直接用jsonresponse对象返回就行了,不需要导入json模块了。
    # 但是同样也是不支持中文的,需要加参数json_dumps_params={'ensure_ascii':False}
    return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False})

    L = [1,2,3,4]
    # json默认是序列化字典用的,如果序列化其他数据类型的话会报错:
    # In order to allow non-dict objects to be serialized set the safe parameter to False.
    # 提示必须要加safe参数
    return JsonResponse(L,safe=False)

FBV

基于函数版的视图任务

def index(request):
    user_dict = {'username':'qinyj','age':18,'hobby':'独角兽的好事'}
    # json数据序列化的时候,如果这个字典里有中文,
    # 那么序列化的时候就不能序列化中文了,需要加参数ensure_ascii=False
    return HttpResponse(json.dumps(user_dict,ensure_ascii=False))
    
    # 同样django帮你想到了这点,直接用jsonresponse对象返回就行了,不需要导入json模块了。
    # 但是同样也是不支持中文的,需要加参数json_dumps_params={'ensure_ascii':False}
    return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False})

    L = [1,2,3,4]
    # json默认是序列化字典用的,如果序列化其他数据类型的话会报错:
    # In order to allow non-dict objects to be serialized set the safe parameter to False.
    # 提示必须要加safe参数
    return JsonResponse(L,safe=False)

然后在urls.py 路由匹配中写匹配规则
url(r'^index/', views.index)

CBV

基于类版的视图任务

# 导入View,继承View类
from django.views import View

class MyLogin(View):
    def get(self,request):
        print("我是MyLog里面的get方法")
        return render(request,'login.html')

    def post(self,request):
        print("我是MyLog里面的post方法")
        return HttpResponse("post")
    
然后在urls.py 路由匹配中写匹配规则,CBV书写方式有所不同
url(r'^login/', views.MyLogin.as_view())
# 通过看源码的执行流程:
# 访问类的属性和方法,方法加括号,执行优先级最高
# 项目一启动 会自动执行as_views方法
# 第一步  会 变形为 views.view
# url(r'login/',views.view),
# 然后进入view函数 --> self.dispatch(request, *args, **kwargs) --> if request.method.lower() in self.http_method_names:
    #             handler = getattr(self, request.method.lower(), self.http_method_not_allowed) --> return handler(request, *args, **kwargs)

CBV源码

我们通过看CBV执行的流程源码看出来,可以思考一个问题,

我们在视图中定义两个方法,get、post

为什么能够根据请求方式的不同,自动执行不同的方法?

django CBV方式执行源码重要部分:

路由层通过匹配
url(r'^login/', views.MyLogin.as_view())
首先遇到类名加括号,执行优先级最高,通过调用as_view得到一个返回值view,把它变形,
url(r'login/',views.view)
然后执行view的方法,会到dispatch方法中执行
判断请求的方式是什么,在不在事先定义好的方法列表里面
然后利用反射得到对请求方式的对象,再次return出去,执行请求方式对象里的内容.

@classonlymethod
def as_view(cls, **initkwargs):
    """
        Main entry point for a request-response process.
        """
    ...
    def view(request, *args, **kwargs):
        self = cls(**initkwargs)
        if hasattr(self, 'get') and not hasattr(self, 'head'):
            self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            return self.dispatch(request, *args, **kwargs)
        ...
        update_wrapper(view, cls.dispatch, assigned=())
        return view
    
 	def dispatch(self, request, *args, **kwargs):
        # 这里判断请求的方式是什么,在不在事先定义好的方法列表里面
        # http_method_names = ['get',
        # 'post', 
        # 'put', 
        # 'patch', 
        # 'delete', 
        # 'head', 
        # 'options', 
        # 'trace']
        
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)

如何给FBV和CBV加装饰器

FBV加装饰器的方式很简单,和之前我们加装饰器没有区别。


# 定义一个计算执行时间的装饰器
def outter(func):
    @wraps(func)
    def inner(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)
        end_time = time.time()
        print('执行时间:',end_time - start_time)
        return res
    return inner


# 普通函数加装饰器
@outter
def index(request):
    user_dict = {'username':'qinyj','age':18,'hobby':'独角兽的好事'}
    # return HttpResponse(json.dumps(user_dict,ensure_ascii=False))
    # json数据序列化的时候,如果这个字典里有中文,
    # 那么序列化的时候就不能序列化中文了,需要加参数ensure_ascii=False


    # 同样django帮你想到了这点,直接用jsonresponse对象返回就行了,不需要导入json模块了。
    # return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False})

    L = [1,2,3,4]
    # json默认是序列化字典用的,如果序列化其他数据类型的话会报错:
    # In order to allow non-dict objects to be serialized set the safe parameter to False.
    # 提示必须要加safe参数
    return JsonResponse(L,safe=False)

那么CBV加加装饰器如何加?

@method_decorator(outter,name='get')

outter:装饰器名称

name=:指定哪个方法使用装饰器

# 定义一个计算执行时间的装饰器
def outter(func):
    @wraps(func)
    def inner(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)
        end_time = time.time()
        print('执行时间:',end_time - start_time)
        return res
    return inner

# 导入装饰器的模块,官方推荐写法 
from django.utils.decorators import method_decorator
# 第一种方式:可以指定给那个方法加
# @method_decorator(outter,name='get')
# @method_decorator(outter,name='post')
# @method_decorator(outter,name='dispatch')
class MyLogin(View):
    # 第二种方式:在此重写父类dispatch方法,做一些操作,给所有的方法都加上装饰器。
    @method_decorator(outter)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
    
    # 第三中方法:可以单独在方法名称上加装饰器
    # @method_decorator(outter)
    def get(self,request):
        print("我是MyLog里面的get方法")
        return render(request,'login.html')

    def post(self,request):
        print("我是MyLog里面的post方法")
		return HttpResponse("post")
    
执行结果:
我是MyLog里面的get方法
执行时间: 0.01500082015991211

我是MyLog里面的post方法
执行时间: 0.0
posted @ 2019-11-26 20:04  GeminiMp  阅读(163)  评论(0编辑  收藏  举报