• 四十三、视图层


    一 视图函数的返回值

    # urls.py
    path('index/', views.index)
    
    • 1
    • 2
    # views.py
    def index(request):
        pass
    
    • 1
    • 2
    • 3

    访问index路由,会报这个视图函数返回的不是一个HttpResponse对象,而是一个None。
    在这里插入图片描述
    言外之意是调用视图函数返回的必须是一个HttpResponse对象。

    # 源码
    
    class HttpResponse(HttpResponseBase):
    	pass
    
    def render(
        request, template_name, context=None, content_type=None, status=None, using=None
    ):
        """
        Return an 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)
    
    
    
    def redirect(to, *args, permanent=False, **kwargs):
        """
        Return an HttpResponseRedirect to the appropriate URL for the arguments
        passed.
        """
        redirect_class = (
            HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
        )
        return redirect_class(resolve_url(to, *args, **kwargs))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    二 视图函数返回json格式数据

    • 方式一:使用json模块
    # urls.py
    
    path('json/', views.json)
    
    • 1
    • 2
    • 3
    # views.py
    
    def json(request):
        user_dict = {"name": "jasper", "age": 18, "hobby": ["read", "run", "篮球"]}
        import json
        res = json.dumps(user_dict, ensure_ascii=False)
        return HttpResponse(res)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    结果:在这里插入图片描述

    • 方式二:使用JsonResponse模块
    # views.py
    
    def json(request):
        user_dict = {"name": "jasper", "age": 18, "hobby": ["read", "run", "篮球"]}
        from django.http import JsonResponse
        return JsonResponse(user_dict)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    怎样解决中文乱码问题?

    # 源码
    
    class JsonResponse(HttpResponse):
    
        def __init__(
            self,
            data,
            encoder=DjangoJSONEncoder,
            safe=True,
            json_dumps_params=None,
            **kwargs,
        ):  # 初始化类对象
            if json_dumps_params is None:  # 当json_dumps_params参数不传时 默认转换成空字典
                json_dumps_params = {}
            kwargs.setdefault("content_type", "application/json")
            # 调用json模块序列化 将json_dumps_params里的关键字参数转换成关键字实参传入dumps函数
            data = json.dumps(data, cls=encoder, **json_dumps_params)
            super().__init__(content=data, **kwargs)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    dumps函数中不保证时ascii码的参数时ensure_ascii=True,只用将这个参数以字典的形式传入即可。

    # views.py
    
    def json(request):
        user_dict = {"name": "jasper", "age": 18, "hobby": ["read", "run", "篮球"]}
        from django.http import JsonResponse
        return JsonResponse(user_dict, json_dumps_params={"ensure_ascii": False})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    • 序列化一个非字典类型的数据时
    # views.py
    
    def json(request):
        user_dict = ["唱", "跳", "rap", "篮球"]
        from django.http import JsonResponse
        return JsonResponse(user_dict, json_dumps_params={"ensure_ascii": False})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    报错信息说,不是一个字典类型对象不能被序列化,需要把safe参数设置成False。

    # 源码
    
    class JsonResponse(HttpResponse):
    
        def __init__(
            self,
            data,
            encoder=DjangoJSONEncoder,
            safe=True,
            json_dumps_params=None,
            **kwargs,
        ):
        	# 这就是抛出异常的代码
        	# 当safe为True并且data的类型不是dict 则会抛出异常
            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."
                )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    查看源码后发现,只需将safe参数改为False即可。

    # views.py
    
    def json(request):
        user_dict = ["唱", "跳", "rap", "篮球"]
        from django.http import JsonResponse
        return JsonResponse(user_dict, json_dumps_params={"ensure_ascii": False}, safe=False)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    三 form表单携带文件数据

    # urls.py
    
    path('form/', views.form)
    
    • 1
    • 2
    • 3
    # views.py
    
    def form(request):
        if request.method == 'GET':
            return render(request, 'form.html')
        print(request.POST)
        return HttpResponse('ok')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    <body>
        <form method="post">
          <div class="form-group">
            <label for="exampleInputEmail1">Email addresslabel>
            <input type="email" name="email" class="form-control" id="exampleInputEmail1" placeholder="Email">
          div>
          <div class="form-group">
            <label for="exampleInputPassword1">Passwordlabel>
            <input type="password" class="form-control" name="password" id="exampleInputPassword1" placeholder="Password">
          div>
          <div class="form-group">
            <label for="exampleInputFile">File inputlabel>
            <input type="file" id="exampleInputFile" name="file">
            <p class="help-block">Example block-level help text here.p>
          div>
          <div class="checkbox">
            <label>
              <input type="checkbox"> Check me out
            label>
          div>
          <button type="submit" class="btn btn-default">Submitbutton>
        form>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述
    在这里插入图片描述
    request.POST拿到的是一个字符串并不是真正的文件对象,如果想拿到真正的数据,必须满足以下条件。

    1. from标签中请求方式必须是post
    2. from标签中必须有属性enctype=“multipart/from-data”
    3. 后端获取文件数据使用request.FILES
    # views.py
    
    def form(request):
        if request.method == 'GET':
            return render(request, 'form.html')
        print(request.POST)
        print(request.FILES)
        return HttpResponse('ok')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    <form method="post" enctype="multipart/form-data">
    
    • 1

    在这里插入图片描述
    可以看到request.FILES拿到的可以看作是一个字典,使用方法和GET、POST一致。

    将JQuery包导入Django中的static文件夹中:

    # views.py
    
    def form(request):
        if request.method == 'GET':
            return render(request, 'form.html')
        file_obj = request.FILES.get('file')
        path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'static', file_obj.name)
        with open(path, 'a', encoding='utf8') as f:
            for i in file_obj:
                f.write(i.decode())
        return HttpResponse('ok')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    在这里插入图片描述

    四 FBV和CBV

    4.1 FBV

    基于函数的视图,上面写的全是FBV的,这里就不在写了。

    4.2 CBV

    基于类的视图:

    • 与特定的HTTP方法(GET、POST等)关联的代码组织能通过单独的方法替换条件分支来解决。
    • 面向对象技术可用于将代码分解为可重用组件。

    本质上来说,基于类的视图允许使用不同的类实例方法响应不同的HTTP请求,而不是在单个视图函数里使用有条件分支的代码。

    因此,在CBV里处理HTTP中的GET和POST的代码应该像下边这么写。

    # views.py
    
    from django.shortcuts import HttpResponse, render
    from django.views import View
    
    
    # Create your views here.
    
    
    class MyView(View):
        def get(self, request):
            return render(request, 'post.html')
    
        def post(self, request):
            return HttpResponse('post result')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    <form action="" method="post">
            <input class="btn btn-default" type="submit" value="Submit">
     form>
    
    • 1
    • 2
    • 3
    # urls.py
    
    from django.urls import path
    from app01.views import MyView
    
    urlpatterns = [
        path('test/', MyView.as_view()),
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    当触发get请求时:
    在这里插入图片描述

    点击submit触发post请求时:
    在这里插入图片描述

    4.3 CBV源码分析

    因为Django的URL解析器期望发送请求和相关参数来调动函数而不是类,基于类的视图有一个as_view()类方法。

    # View类中的as_view方法
    
    class View:
    
    	...
    
        @classonlymethod
        def as_view(cls, **initkwargs):
        	...
            return view
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    1. 当一个URL被匹配时,会调用我们自己写的类MyView中的as_view方法,但是MyView中没有此方法,但是MyView继承了View类,其实就是执行了View类中的as_view,并返回一个view函数。
    # View类中的view函数
    
       def view(request, *args, **kwargs):
           self = cls(**initkwargs)
           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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. 执行view函数,先实例化一个MyView的对象self,再用这个对象调用setup方法(对象再找一个方法,先从对象本身找,再找产生对象的类,没有再找类的父类),这里的setup是View中的。
    # View类中的setup方法
    
    def setup(self, request, *args, **kwargs):
         """Initialize attributes shared by all view methods."""
         if hasattr(self, "get") and not hasattr(self, "head"):
             self.head = self.get
         self.request = request
         self.args = args
         self.kwargs = kwargs
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 运行setup初始MyView产生的对象,然后调用dispatch方法。
    # View类中的dispatch方法
    
    
    http_method_names = [
            "get",
            "post",
            "put",
            "patch",
            "delete",
            "head",
            "options",
            "trace",
        ]
    
     def dispatch(self, request, *args, **kwargs):
         # Try to dispatch to the right method; if a method doesn't exist,
         # defer to the error handler. Also defer to the error handler if the
         # request method isn't on the approved list.
         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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    1. 判断请求方式是不是在 http_method_names 中,如果在,就获取对象的该属性,因为MyView中定义了get方法和post方法,所以对象获取的就是自己本身的,执行并返回。如果不存在就会引发HttpResponseNotAllowed。
  • 相关阅读:
    Beego之Beego简介和安装
    顶刊BMJ杂志推荐方法学文章!断点回归方法介绍
    DBeaver工具在无网络的情况下连接clickhouse方法
    RT thread 信号量操作
    mysql根据逗号将一行数据拆分成多行数据,并展示其他列
    UnrealEngine - 网络同步入门
    java架构知识-数据库(学习笔记)
    CAD Exchanger SDK 3.13 Crack
    【Unity3D赛车游戏优化篇】新【八】汽车实现镜头的流畅跟随,以及不同角度的切换
    EasyExcel 复杂数据导出
  • 原文地址:https://blog.csdn.net/weixin_68531269/article/details/126665678