django之视图层

视图层必会三板斧

用来处理请求的视图函数都必须返回HttpResponse对象
1. return HttpResponse()  # HttpResponse本身是一个类,类加括号产生对象

2. return render()  
    源码见图二,render的源码是一个函数,返回值是HttpResponse(content, content_type, status),产生的也是HttpResponse对象

3. return redirect()  
    源码见图二,redirect的源码是一个函数,里面写了一个三元表达式 
    redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
    产生的结果都是HttpResponse,那么其返回值也是HttpResponse对象

图二

image

JsonResponse对象

正常情况下我们要给浏览器返回一个json格式的字符串需要先把字符串转为json格式然后再发送给浏览器
django中有一个JsonResPonse对象它可以直接完成上面的操作\
下面的是JsonResponse的源码
class JsonResponse(HttpResponse):
    def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
                 json_dumps_params=None, **kwargs):
        if safe and not isinstance(data, dict):
            raise TypeError(
                'In order to allow non-dict objects to be serialized set the '
                'safe parameter to False.'
            )
        if json_dumps_params is None:
            json_dumps_params = {}
        kwargs.setdefault('content_type', 'application/json')
        data = json.dumps(data, cls=encoder, **json_dumps_params)
        super().__init__(content=data, **kwargs)
1.使用JsonResponse传汉字,加一个json_dumps_params = {'ensure_ascii': False}
    其它的一些可能需要使用到的参数如果没有默认的可以使用json_dumps_params
2.针对非字典的其它可以被序列化的数据需要修改safe参数为False  safe=False

from django.http import JsonResponse
def index(request):
    a = {'name': 'jason老师'}
    b = [1, 2, 3, 4]
    # return JsonResponse(a, json_dumps_params={'ensure_ascii': False})
    return JsonResponse(b, json_dumps_params={'ensure_ascii': False}, safe=False)

request对象获取文件

form表单携带文件需要做到以下几点
    1.method必须是post
    2.enctype必须是multipart/form-data  
    # 在form表单中修改enctype参数为multipart/form-data,默认是application/x-www-form-urlencoded
django后端需要通过request.FILES来获取文件类型的数据,获取到的是一个文件对象
接收文件和GET、POST一样用get
file_obj = request.FILES.get('file')
file_obj.name  # 获取文件名
# 文件对象支持for循环一行行读取文件内容

FBV与CBV

FBV  基于函数的视图
    def index(request): return HttpResponse对象
    
CBV  基于类的视图
    from diango import views
    class MyLoginView(views.View):
        def get(self, request):
            return HttpResponse('from CBV get function')
        
        def post(self, request):
            return HttpResponse('from CBV post function')
    path('login/', views.MyLoginView.as_view())
    使用CBV会根据请求方法的不同自动匹配对应的方法并执行

CBV源码解析

1.先看路由匹配
    path('login/', views.MyLoginView.as_view())
        1.MyLoginView使我们自己定义的类,类点一个名字涉及到名字的查找顺序,自己没有往父类找
        2.类名点名字加括号调用表明是一个绑定给类的方法(@classmethod)
2.函数名或方法名加括号执行优先级最高,项目一启动就会自动最先执行as_view方法
    通过查看源码可以看到as_view方法的返回值是定义在as_view内部的view方法,那么我们的路由匹配就可以看成是
    path('login/', views.view)  # 由此可以看出CBV的本质还是FBV
    源码:
        @classonlymethod
            def as_view(cls, **initkwargs):
                """Main entry point for a request-response process."""
                for key in initkwargs:
                    if key in cls.http_method_names:
                        raise TypeError("You tried to pass in the %s method name as a "
                                        "keyword argument to %s(). Don't do that."
                                        % (key, cls.__name__))
                    if not hasattr(cls, key):
                        raise TypeError("%s() received an invalid keyword %r. as_view "
                                        "only accepts arguments that are already "
                                        "attributes of the class." % (cls.__name__, key))

                def view(request, *args, **kwargs):
                    self = cls(**initkwargs)
                    if hasattr(self, 'get') and not hasattr(self, 'head'):
                        self.head = self.get
                    self.setup(request, *args, **kwargs)
                    if not hasattr(self, 'request'):
                        raise AttributeError(
                            "%s instance has no 'request' attribute. Did you override "
                            "setup() and forget to call super()?" % cls.__name__
                        )
                    return self.dispatch(request, *args, **kwargs)
                view.view_class = cls
                view.view_initkwargs = initkwargs

                # take name and docstring from class
                update_wrapper(view, cls, updated=())

                # and possible attributes set by decorators
                # like csrf_exempt from dispatch
                update_wrapper(view, cls.dispatch, assigned=())
                return view
3.由第二步可以得到浏览器访问login路由需要执行view函数
    1.执行view函数会产生一个我们自己编写的类的对象
    2.这个对象会调用dispatch方法
    源码:
        def view(request, *args, **kwargs):
        self = cls(**initkwargs)  # cls是我们自己编写的类,这一步是产生一个我们自己编写的类的对象
        if hasattr(self, 'get') and not hasattr(self, 'head'):
            self.head = self.get
        self.setup(request, *args, **kwargs)
        if not hasattr(self, 'request'):
            raise AttributeError(
                "%s instance has no 'request' attribute. Did you override "
                "setup() and forget to call super()?" % cls.__name__
            )
        return self.dispatch(request, *args, **kwargs)  # 我们自己编写的类的对象调用dispath方法
4.由于我们自己编写的类中没有dispatch方法,所以从父类中找
    通过研究父类中的dispatch方法可以知道该方法是获取当前的请求方法并转小写,然后利用反射获取类中对应的方法并执行
    源码:
            def dispatch(self, request, *args, **kwargs):
            # 判断转小写之后的请求方法是不是属于八个正常的请求方法
                if request.method.lower() in self.http_method_names:
                    # getattr(对象,'get', '获取不到的报错信息')
                    handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
                else:
                    handler = self.http_method_not_allowed
                return handler(request, *args, **kwargs)  # 执行反射之后获取到的方法
posted on 2023-04-08 20:39  zyg111  阅读(13)  评论(0编辑  收藏  举报