• Django——视图层


    一. 三板斧

    强调: 视图函数必须要返回一个HttpResponse对象. 研究三者的源码发现默认其他2种默认都是继承了HttpResponse. 在没有指定返回值的情况下会抛出如下异常, 从中我们更加确定了这点:

    The view app01.views.index didn't return an HttpResponse object. It returned None instead.

    1. """
    2. HttpResponse
    3. 返回字符串类型
    4. render
    5. 返回html页面 并且在返回给浏览器之前还可以给html文件传值
    6. redirect
    7. 重定向
    8. """
    9. # render简单内部原理
    10. from django.template import Template,Context
    11. Temp = Template('

      {{ user }}

      '
      )
    12. con = Context({'user':{'username':'jason','password':123}})
    13. res = Temp.render(con)
    14. print(res)
    15. return HttpResponse(res)

    二. JsonResponse对象

    1. json格式的数据有什么用?
    2. 前后端数据交互需要使用到json作为过渡 实现跨语言传输数据
    3. 前端序列化
    4. JSON.stringify() json.dumps()
    5. JSON.parse() json.loads()
    1. def ab_json(request):
    2. from django.shortcuts import HttpResponse
    3. user_dict = {'username': 'jason', 'password': '123', 'hobby': '他喜欢跑步, 我们称他为跑王'}
    4. # 一. 使用jason将数据格式转换成序列化类型, 再使用HttpResponse将该字符串返回
    5. # import json
    6. # json_str = json.dumps(user_dict, ensure_ascii=False)
    7. # return HttpResponse(json_str)
    8. # 二. 使用JsonResponse实现如上功能.
    9. from django.http import JsonResponse
    10. '''
    11. :param json_dumps_params: A dictionary of kwargs passed to json.dumps(). # 一个kwarg字典传递给json.dumps()。
    12. data = json.dumps(data, cls=encoder, **json_dumps_params)
    13. '''
    14. # return JsonResponse(user_dict, json_dumps_params={'ensure_ascii': False})
    15. li = [111, 222, 333, 444, '他喜欢跑步, 我们称他为跑王']
    16. '''
    17. if safe and not isinstance(data, dict):
    18. raise TypeError(
    19. 'In order to allow non-dict objects to be serialized set the '
    20. 'safe parameter to False.' # 为了允许非dict对象被序列化,设置safe参数为False。
    21. )
    22. '''
    23. return JsonResponse(li, safe=False, json_dumps_params={'ensure_ascii': False})
    24. # 总结
    25. '''
    26. 1. JsonResponse默认只能传递字典类型,如果要传递非字典类型需要设置一下safe关键字参数。
    27. response = JsonResponse([1, 2, 3], safe=False)
    28. 2. JsonResponse序列化如果想要中文不编码需要指定ensure_ascii为False
    29. return JsonResponse(user_dict, json_dumps_params={'ensure_ascii': False})
    30. '''

    三. form表单上传文件及后端如何操作

    1. form表单上传文件类型的数据
    2. 1. method必须指定成post
    3. 2. enctype指定属性值为`multipart/form-data`
    1. def ab_file(request):
    2. if request.method == "POST":
    3. print(request.POST) #
    4. print(request.FILES) # , , ...]}>
    5. # 一. 获取MultiValueDict文件对象列表中最后一个文件对象
    6. file_obj = request.FILES.get('file')
    7. print(file_obj.name) # error.html
    8. # 二. 获取MultiValueDict文件对象列表中多有文件
    9. '''
    10. file_obj_list = request.FILES.getlist('file')
    11. print(file_obj_list[0]) # index.html
    12. print(file_obj_list[1]) # error.html
    13. '''
    14. # 三. 保存文件
    15. # 写法一:
    16. '''
    17. with open(file_obj.name, 'wb') as f:
    18. for line in file_obj:
    19. f.write(line)
    20. '''
    21. # 写法二: 官方推荐写法
    22. '''
    23. def chunks(self, chunk_size=None):
    24. self.file.seek(0)
    25. yield self.read()
    26. '''
    27. with open(file_obj.name, 'wb') as f:
    28. for line in file_obj.chunks():
    29. f.write(line)
    30. return render(request, 'form.html')

    四. request对象方法

    1. 常用方法

    1. print(request.method) # GET 返回大写的字符串格式的请求方式
    2. print(request.GET) # 返回QueryDict对象
    3. print(request.POST)
    4. print(request.FILES) # , , ...]}>
    5. print(request.path) # /app02/ab_request/ 只能拿到路由
    6. print(request.path_info) # /app02/ab_request/
    7. print(request.get_full_path()) # /app02/ab_request/?username=jason&password=123 可以拿到路由, 又可以拿到路由?号后面的参数
    8. print(request.body) # 原生浏览器发送过来的二进制数据

     

    2. request.MEAT

    1. print(request.MEAT) # HTTP请求的其他东西,放在里面,如: 客户端ip地址:REMOTE_ADDR
    2. request.META: {
    3. 'ALLUSERSPROFILE': 'C:\\ProgramData',
    4. 'ASL.LOG': 'Destination=file',
    5. 'COMMONPROGRAMFILES': 'C:\\Program Files\\Common Files',
    6. 'COMMONPROGRAMFILES(X86)': 'C:\\Program Files (x86)\\Common Files',
    7. 'COMMONPROGRAMW6432': 'C:\\Program Files\\Common Files',
    8. 'COMPUTERNAME': 'LAPTOP-EI2EE90I',
    9. 'COMSPEC': 'C:\\WINDOWS\\system32\\cmd.exe',
    10. 'CYGWIN': 'mintty',
    11. 'DJANGO_SETTINGS_MODULE': 'request_data.settings',
    12. 'DRIVERDATA': 'C:\\Windows\\System32\\Drivers\\DriverData',
    13. 'HOMEDRIVE': 'C:',
    14. 'IDEA_INITIAL_DIRECTORY': 'Z:\\pycharm-professional\\PyCharm 2019.3.3\\bin',
    15. 'LOGONSERVER': '\\\\LAPTOP-EI2EE90I',
    16. 'NUMBER_OF_PROCESSORS': '4',
    17. 'OS': 'Windows_NT',
    18. 'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC',
    19. 'PROCESSOR_ARCHITECTURE': 'AMD64',
    20. 'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 158 Stepping 9, GenuineIntel',
    21. 'PROCESSOR_LEVEL': '6',
    22. 'PROCESSOR_REVISION': '9e09',
    23. 'PROGRAMDATA': 'C:\\ProgramData',
    24. 'PROGRAMFILES': 'C:\\Program Files',
    25. 'PROGRAMFILES(X86)': 'C:\\Program Files (x86)',
    26. 'PROGRAMW6432': 'C:\\Program Files',
    27. 'PSMODULEPATH': 'C:\\Program Files\\WindowsPowerShell\\Modules;C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\Modules',
    28. 'PUBLIC': 'C:\\Users\\Public',
    29. 'PYCHARM': 'Z:\\pycharm-professional\\PyCharm 2019.3.3\\bin;',
    30. 'PYCHARM_DISPLAY_PORT': '63342',
    31. 'PYCHARM_HOSTED': '1',
    32. 'PYTHONIOENCODING': 'UTF-8',
    33. 'PYTHONPATH': 'X:\\Django\\request_data;Z:\\pycharm-professional\\PyCharm 2019.3.3\\plugins\\python\\helpers\\pycharm_matplotlib_backend;Z:\\pycharm-professional\\PyCharm 2019.3.3\\plugins\\python\\helpers\\pycharm_display',
    34. 'PYTHONUNBUFFERED': '1',
    35. 'SESSIONNAME': 'Console',
    36. 'SYSTEMDRIVE': 'C:',
    37. 'SYSTEMROOT': 'C:\\WINDOWS',
    38. 'USERDOMAIN': 'LAPTOP-EI2EE90I',
    39. 'USERDOMAIN_ROAMINGPROFILE': 'LAPTOP-EI2EE90I',
    40. 'WINDIR': 'C:\\WINDOWS',
    41. 'RUN_MAIN': 'true',
    42. 'SERVER_NAME': 'LAPTOP-EI2EE90I',
    43. 'GATEWAY_INTERFACE': 'CGI/1.1',
    44. 'SERVER_PORT': '8011',
    45. 'REMOTE_HOST': '',
    46. 'CONTENT_LENGTH': '',
    47. 'SCRIPT_NAME': '',
    48. 'SERVER_PROTOCOL': 'HTTP/1.1',
    49. 'SERVER_SOFTWARE': 'WSGIServer/0.2',
    50. 'REQUEST_METHOD': 'GET',
    51. 'PATH_INFO': '/app01/index/index_2/three_custom_tag/',
    52. 'QUERY_STRING': 'username=egon',
    53. 'REMOTE_ADDR': '127.0.0.1',
    54. 'CONTENT_TYPE': 'text/plain',
    55. 'HTTP_HOST': '127.0.0.1:8011',
    56. 'HTTP_CONNECTION': 'keep-alive',
    57. 'HTTP_PRAGMA': 'no-cache',
    58. 'HTTP_CACHE_CONTROL': 'no-cache',
    59. 'HTTP_UPGRADE_INSECURE_REQUESTS': '1',
    60. 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36',
    61. 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
    62. 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br',
    63. 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9,en;q=0.8',
    64. 'HTTP_COOKIE': 'csrftoken=ocjhW1fEWTsaZvJIXqi9gXB31Fu3mdoJORP0vqkY6aNnT7JCo0WzrcV92GTlSI7K; token_id="{\\"userID\\": 1}|43094b6783dcfe87b55d8d8277c3b784:1jqpyY:11xEFuh0GUKLdsXL3wU7Vit10hM"',
    65. 'wsgi.input': < _io.BufferedReader name = 752 > ,
    66. 'wsgi.errors': < _io.TextIOWrapper name = ''
    67. mode = 'w'
    68. encoding = 'UTF-8' > ,
    69. 'wsgi.version': (1, 0),
    70. 'wsgi.run_once': False,
    71. 'wsgi.url_scheme': 'http',
    72. 'wsgi.multithread': True,
    73. 'wsgi.multiprocess': False,
    74. 'wsgi.file_wrapper': < class 'wsgiref.util.FileWrapper' > ,
    75. 'CSRF_COOKIE': 'ocjhW1fEWTsaZvJIXqi9gXB31Fu3mdoJORP0vqkY6aNnT7JCo0WzrcV92GTlSI7K'
    76. }

    3. 关于QueryDict对象的拓展

    1. '''
    2. 1. QueryDict本质也是继承字典, 但是比原生dict强大, 这个QueryDict就不能被修改, 改了就会抛出异常.
    3. 2. 如果要想修改, 就应该对QueryDict对象调用.copy()方法.
    4. '''
    5. print(type(request.POST)) #
    6. from django.http.request import QueryDict
    7. # QueryDict本质也是继承字典, 但是比原生dict强大, 这个QueryDict就不能被修改, 改了就会抛出异常.
    8. request.POST.pop('username') # AttributeError: This QueryDict instance is immutable
    9. # 如果要想修改, 就应该对QueryDict对象调用.copy()方法.
    10. new_query_dict = request.POST.copy()
    11. print('new_query_dict:', new_query_dict)
    12. print(new_query_dict.pop('username')) # [''] (我们发现copy以后就可以修改了)

    4. request.FILES方法补充

    1. print('request.FILES:', request.FILES.get('avatar'), type(request.FILES), type(request.FILES.get('avatar')))
    2. from django.utils.datastructures import MultiValueDict
    3. from django.core.files.uploadedfile import InMemoryUploadedFile
    4. file_obj = request.FILES.get('avatar')
    5. print(file_obj.file, # <_io.BytesIO object at 0x000001DCC1CAC0A0>
    6. file_obj.field_name, # avatar
    7. file_obj.name, # img2.jpg
    8. file_obj.content_type, # image/jpeg
    9. file_obj.size, # 3855
    10. file_obj.charset) # None

    五. FBV与CBV

    1. FBV与CBV介绍与CBV基本使用

    1. '''
    2. FBV全称Function Based View CBV全称Function Based View. FBV和CBV各有千秋
    3. # CBV特点: 能够直接根据请求方式的不同直接匹配到对应的方法执
    4. '''
    5. # 路由层使用
    6. url(r'^my_index/', views.MyIndex.as_view())
    7. # 视图层使用
    8. from django.views import View
    9. class MyIndex(View):
    10. def get(self, request):
    11. pass
    12. def post(self, request):
    13. pass

    2. CBV源码剖析

    1. # 突破口: urls.py
    2. url(r'^login/', views.MyLogin.as_view())
    3. # 强调: 面向对象属性方法查找顺序!!!!!!!!
    4. """
    5. 先从对象自己找
    6. 再去产生对象的类里面找
    7. 之后再去父类找
    8. ....
    9. """
    10. 加载时: views.MyLogin.as_view()
    11. 匹配前: views.view
    12. 匹配后: views.view(request, *args, **kwargs)
    13. # 第一步: 返回对象方法dispatch
    14. '''
    15. 查找顺序: self.dispatch
    16. self -> MyLogin -> View -> dispatch
    17. '''
    18. def view(request, *args, **kwargs):
    19. self = cls(**initkwargs) # cls=MyLogin
    20. if hasattr(self, 'get') and not hasattr(self, 'head'):
    21. self.head = self.get
    22. self.request = request
    23. self.args = args
    24. self.kwargs = kwargs
    25. return self.dispatch(request, *args, **kwargs)
    26. # 第二步: 由request对象获取请求方式, 再转化成小写, 再进行判断是否存在所支持的请求方式,
    27. 存在进行反射通过方法的字符串去获取MyLogin中存在的方法函数的内存地址.
    28. 不存在返回错误信息.
    29. 最后拿到函数得内存地址加括号传参调用, 这样就实现了浏览器是什么请求, 那么视图层定义的MyLogin类中定义的方法名中的函数.
    30. '''
    31. 查找顺序: self.http_method_names
    32. self -> MyLogin -> View -> http_method_names
    33. http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    34. 查找顺序: getattr(self, request.method.lower(), self.http_method_not_allowed)
    35. self -> MyLogin
    36. self = handler(request, *args, **kwargs)
    37. '''
    38. def dispatch(self, request, *args, **kwargs):
    39. if request.method.lower() in self.http_method_names:
    40. handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    41. else:
    42. handler = self.http_method_not_allowed
    43. return handler(request, *args, **kwargs)

    3. CBV源码剖析流程

    1. # 特点: 能够更具请求方式的不同自动匹配类中对应的方法的执行
    2. # 突破口: urls.py
    3. # 关键点: dispatch方法
    4. # 注意: 面寻对象属性方法查找的顺序
    5. 对象 -> 对象的类 -> 父类....
    6. # 分析源码执行流程:
    7. 路由层: url(r'^index/, views.MyIndex.as_view())
    8. 视图层:
    9. from django.views import View
    10. def MyIndex(View):
    11. def get(self, request):
    12. pass
    13. 第一步: 项目启动, urls.py脚本被加载, as_view是绑定了一个函数的内存地址
    14. 通过内存地址加括号就会直接执行函数体代码. 执行函数体代码MyIndex是一个类
    15. `类.as_view()` 就是触发类中的静态方法或者类方法. MyIndex中并没有定义
    16. 这个方法, 那么就去继承的View类中找, 发现View类中有这个方法, 且这个方法是一个类方法.
    17. 第二步: 类中方法执行完毕以后返回一个view, 那么就可以理解为项目启动加载了urls.py代码以后放在这里的
    18. 是`views.view`.
    19. 第三步: 浏览器发起请求, 由路由器筛选匹配, 匹配到了那么就会加括号执行与之绑定的视图函数
    20. 我们这里现在是`views.view`, 那么我们找view. 之前返回给我们view是在View类中
    21. 我们找到View类, 找到View类以后执行以后, 我们看到有cls, self. 之前我们是用类调用了类方法,
    22. 这时这里的cls就是我们的MyLogin类, 因为之前调用类方法as_view()时将cls包给了view方法,
    23. 那么self就是MyLogin实例化的对象, 最后又返回了一个self.dispath.
    24. 第四步: 又是面向对象的属性查找. 我们找self, 之前我们说self就是MyLogin实例化的对象, 那么我们到
    25. 其实例化的对象中找, 发现并没有. 接着我们到其类中MyLogin中找, 发现也没有. 那么我们继续找其继承的类
    26. View类中找, 发现有. 那么看到第一句话发现是request.method获取请求方式的大写字串, 再转小写,
    27. in判断是否在后面的http_method_names, 而http_method_names这个列表当中,
    28. 包含了8个请求的请求的小写字符串格式内容, 通过判断如果在, 那么就接着会使用反射方法拿到对应的handler这个方法的内存地址.
    29. 这里我们可以理解为当浏览器发起get请求时, 那么handler就是MyLogin中的你定义的get方法, 最后返回一个handler(request, *args, **kwargs),
    30. 这就是调用你定义的get方法了, 这就实现了浏览器什么请求来, 就调用什么方法去执行,
    31. 但是如果判断错误就会触发http_method_not_allowed这个错误的提示返回给浏览器,
    32. getattr反射方法的第二个参数也是在没有找到的情况下返回http_method_not_allowed.

    六. 总结

    1. # 三板斧
    2. 三板斧: HttpResponse, render, redirect
    3. 第一点: 视图函数本质就是返回HttpResponse对象, render, redirect都继承了HttpResponse类.
    4. 第二点: render内部原理
    5. from templates import Template, Context
    6. temp = Template("

      {{ user }}

      "
      )
    7. con = Context({'user': {'username': '鸡哥', 'info': '人称跑王的鸡哥!'}})
    8. res = temp.render(con)
    9. return HttpResponse(res)
    10. # JsonResponse对象
    11. # json格式的作用:
    12. 跨语言之间的数据传输. 不同语言之间序列化成json这种中间格式,
    13. 再转换成二进制进行网络传输, 接收方收到以后, 通过它的反序列化,
    14. 就可以拿到属于它自己的数据格式.
    15. # 前后端序列化, 反序列列化对比:
    16. JSON.stringify json_str = json.dumps()
    17. JSON.parse json.loads(json_str)
    18. # JsonResponse使用
    19. from django.http import JsonResponse
    20. def index(request):
    21. # 方式一: 传入字典
    22. '''
    23. 内部原理:
    24. :param json_dumps_params: A dictionary of kwargs passed to json.dumps(). # 一个kwarg字典传递给json.dumps()。
    25. data = json.dumps(data, cls=encoder, **json_dumps_params)
    26. '''
    27. user_dict = {'username': 'jason', 'password': '123', 'hobby': '他喜欢跑步, 我们称他为跑王'}
    28. return JsonResponse(user_dict, json_dumps_params={'ensure_ascii': False})
    29. # 方式二: 传入非字典
    30. '''
    31. 内部原理:
    32. if safe and not isinstance(data, dict):
    33. raise TypeError(
    34. 'In order to allow non-dict objects to be serialized set the '
    35. 'safe parameter to False.' # 为了允许非dict对象被序列化,设置safe参数为False。
    36. )
    37. '''
    38. li = [111, 222, 333, 444, '他喜欢跑步, 我们称他为跑王']
    39. return JsonResponse(li, safe=False, json_dumps_params={'ensure_ascii': False})
    40. # form表单上传文件后端操作
    41. 第一步: form表单必须指定请求方式为post, enctype编码必须指定为multipart/form-data
    42. 第二步: 视图层使用FILES接收文件对象列表集合, 使用get获取对象列表集合最后一个文件对象, 使用getlist获取对象列表集合中所有文件对象
    43. def ab_file(request):
    44. if request.method == "POST":
    45. # 1. 获取
    46. file_obj_list = request.FILES
    47. last_file_obj = file_obj_list.get('file')
    48. all_file_obj = file_obj_list.getlist('file')
    49. # 2. 保存到本地
    50. # 第一种写法:
    51. with open(last_file_obj.name, 'wb') as f:
    52. for line in f:
    53. f.write(line)
    54. # 第二种写法: 官方推荐
    55. '''
    56. 内部实现原理:
    57. def chunks(self, chunk_size=None):
    58. self.file.seek(0)
    59. yield self.read()
    60. '''
    61. with open(last_file_obj.name, 'wb') as f:
    62. for line in file_obj_list.chunks():
    63. f.write(line)
    64. return render(request, 'form.html')
    65. # request对象方法
    66. request.method 获取大写字符串格式的请求方式
    67. request.POST 获取QueryDict对象, 包含url中?好后的所有参数形信息
    68. request.GET 获取QueryDict对象, 包含参数信息
    69. request.FILES 获取文件对象列表集合
    70. request.body 获取原生浏览器发送过来的二进制数据
    71. request.path 获取路由
    72. request.path_info 获取路由
    73. request.get_path_full() 获取路由+参数
    74. request.MEAT 获取HTTP请求的其它剩余东西
    75. # FBV与CBV
    76. FBV 全称 Function Based View 基于函数的视图
    77. CBV 全称 Class Based View 基于类的视图
    78. CBV特点: 内部原理能够直接更具请求方式的不同获取的字符串, 进而使用反射隐射成对应的对象的方法
    79. # 路由层使用
    80. url(r'^my_index/', views.MyIndex.as_view())
    81. # 视图层使用
    82. from django.views import View
    83. class MyIndex(View):
    84. def get(self, request):
    85. pass
    86. def post(self, request):
    87. pass

  • 相关阅读:
    SpringBoot实现发送验证码功能
    如何设置Linux的语言环境
    继电器的故障处理
    协议-SSL协议-基础概念01-SSL位置-协议套件-握手和加密过程-对比ipsec
    MySQL主从搭建--保姆级教学
    STM32不使用 cubeMX实现外部中断
    小程序配置服务器域名的详细步骤与例子
    创建型设计模式之建造者模式
    Vue框架--收集表单数据
    互联网行业中产品经理常用的专业术语有哪些?
  • 原文地址:https://blog.csdn.net/m0_71115526/article/details/134398705