#前言

为什么要配置一个view模板(视图模板)?

  1. 接口开发更加简便,不用单独编写增删改查接口的视图;
  2. 在对应应用下的 views.py 文件中编写接口视图函数时,直接继承 视图模板类 就可以了
  3. 继承 视图模板类 后,这个视图函数(接口)实现了增删改查(POST、DELETE、PUT、GET)功能

1、视图模板文件配置(基础版本)

  • 新建一个公共代码文件夹 common 文件夹
  • 在 common 文件夹中新建一个公共的视图模板custom_class.py文件(名字自定义即可);
  • 在这个文件中定义一个公共的视图模板类(类名自定义即可)。

1.1、视图模板类 的优点:

  1. 接口开发更加简便,不用单独编写增删改查接口;
  2. 在对应应用下的 views.py 文件中编写接口视图函数时,直接继承 视图模板类 就可以了
  3. 继承 视图模板类 后,这个视图函数(接口)实现了增删改查(POST、DELETE、PUT、GET)功能

1.2、视图模板类源码

  1. from django.views import View
  2. from django.core.paginator import Paginator
  3. from django.db.models import Q
  4. from django.http.response import JsonResponse
  5. from common.utils import model_to_dict # 导入自定义函数 model_to_dict
  6. class ThzView(View):
  7. # 实现(增删改查)接口的 视图模板类(支持分页、模糊/精确查询)
  8. search_fields = [] # 指定哪些字段支持模糊查询
  9. filter_fields = [] # 指定哪些字段支持精确查询
  10. form_class = None # 指定的form 类
  11. model_class = None # 指定的model类
  12. def get(self, request):
  13. # 实现查询数据功能的 视图模板方法(支持分页、模糊/精确查询)
  14. limit = request.GET.get("limit", 10)
  15. page = request.GET.get("page", 1)
  16. search = request.GET.get("search")
  17. query_dict = {} # {id:1,name:xxx}
  18. q = Q() # None
  19. for field in self.filter_fields:
  20. value = request.GET.get(field)
  21. if value != None:
  22. query_dict[field] = value
  23. if search:
  24. for field in self.search_fields:
  25. d = {"%s__contains" % field: search}
  26. q = q | Q(**d)
  27. # all_data = models.Grade.objects.filter(q).filter(**query_dict) #先模糊,后精确
  28. all_data = self.model_class.objects.filter(**query_dict).filter(q) # 先精确,后模糊
  29. paginator = Paginator(all_data, limit)
  30. page_data = paginator.get_page(page) # [<grade<1>,<garde2>]
  31. data_list = [model_to_dict(data) for data in page_data]
  32. data = {"code": 0, "msg": "查询成功", "data": data_list, "count": paginator.count}
  33. return JsonResponse(data)
  34. def post(self, request):
  35. # 实现新增数据功能的 视图模板方法
  36. form = self.form_class(request.POST,files=request.FILES)
  37. # files=request.FILES 是为了将请求中的文件参数传递进来
  38. if form.is_valid():
  39. obj = form.save() # 保存到数据库
  40. return JsonResponse({"code": 0, "msg": "操作成功", "id": obj.id})
  41. return JsonResponse({"code": -1, "msg": form.errors.get_json_data()})
  42. # form,model
  43. def put(self, request):
  44. # 实现修改数据功能的 视图模板方法
  45. id = request.PUT.get("id")
  46. if not id:
  47. return JsonResponse({"code": -1, "msg": "请传入要修改的id"})
  48. if not id.isdigit():
  49. return JsonResponse({"code": -1, "msg": "id是数字"})
  50. query_set = self.model_class.objects.filter(id=id)
  51. if not query_set.exists():
  52. return JsonResponse({"code": -1, "msg": "要修改的id不存在"})
  53. grade = query_set.first()
  54. form = self.form_class(request.PUT, instance=grade,files=request.FILES)
  55. # files=request.FILES 是为了将请求中的文件参数传递进来
  56. if form.is_valid():
  57. obj = form.save() # 保存到数据库
  58. return JsonResponse({"code": 0, "msg": "操作成功", "id": obj.id})
  59. return JsonResponse({"code": -1, "msg": form.errors.get_json_data()})
  60. # model Grade
  61. def delete(self, request):
  62. # 实现删除数据功能的 视图模板方法
  63. id = request.GET.get("id")
  64. if not id:
  65. return JsonResponse({"code": -1, "msg": "请传入要修改的id"})
  66. if not id.isdigit():
  67. return JsonResponse({"code": -1, "msg": "id是数字"})
  68. query_set = self.model_class.objects.filter(id=id)
  69. if not query_set.exists():
  70. return JsonResponse({"code": -1, "msg": "要修改的id不存在"})
  71. query_set.delete()
  72. return JsonResponse({"code": 0, "msg": "删除成功!"})

1.3、视图函数继承视图模板类

  • 使用CBV:Class Based View(基于类的视图)开发
  • 在 CBV 视图类中继承视图模板类即可
    • 继承后,这个视图拥有了视图模板类的 增删改查功能

应用视图文件中,编写视图函数,开发接口

  1. from common.custom_class import ThzView
  2. # 从公共文件夹下的 公共类文件里 导入视图模板类
  3. class StudentView(ThzView): # 实现了学生信息增删改查功能的接口
  4. # 继承这个 视图模板类
  5. search_fields = ["name", "phone"]
  6. # 指定哪些字段支持模糊查询
  7. filter_fields = ["id","grade"]
  8. # 指定哪些字段支持精确查询
  9. form_class = forms.StudentForm
  10. # 指定校验的form类
  11. model_class = models.Student
  12. # 指定model模型类(接口要操作的数据表)
  13. class GradeView(ThzView): # 实现了班级信息增删改查功能的接口
  14. search_fields = ["name", "desc"]
  15. filter_fields = ["id"]
  16. form_class = forms.GradeForm
  17. model_class = models.Grade

2、视图模板文件优化(优化版本)

2.1、视图模板类 的优点:

  1. 接口开发更加简便,不用单独编写增删改查接口;
  2. 在对应应用下的 views.py 文件中编写接口视图函数时,直接继承 视图模板类 就可以了
  3. 继承 视图模板类 后,这个视图函数(接口)实现了增删改查(POST、DELETE、PUT、GET)功能
  4. 将模板视图的功能拆分,实现了按需继承(增删改查功能可单独配置)

2.2、视图模板类(优化版)源码

  1. from django.views import View
  2. from django.core.paginator import Paginator
  3. from django.db.models import Q
  4. from django.http.response import JsonResponse
  5. from .utils import model_to_dict
  6. class BaseView(View):
  7. # 接口视图模板的基类
  8. #(必须继承的)
  9. search_fields = [] # 指定哪些字段支持模糊查询
  10. filter_fields = [] # 指定哪些字段支持精确查询
  11. form_class = None # 指定的form(forms校验 类)
  12. model_class = None # 指定的model(模型类)
  13. class GetView:
  14. # 实现查询接口的 视图模板类(支持分页、模糊/精确查询)
  15. # (可选继承)
  16. def get(self, request):
  17. limit = request.GET.get("limit", 10) # 每页多少条数据
  18. page = request.GET.get("page", 1) # 第几页
  19. search = request.GET.get("search") # 模糊查询的内容
  20. query_dict = {} # {id:1,name:xxx}
  21. q = Q() # None
  22. for field in self.filter_fields:
  23. value = request.GET.get(field)
  24. if value != None:
  25. query_dict[field] = value
  26. if search:
  27. for field in self.search_fields:
  28. d = {"%s__contains" % field: search}
  29. q = q | Q(**d)
  30. all_data = self.model_class.objects.filter(**query_dict).filter(q)
  31. # 先精确,后模糊
  32. paginator = Paginator(all_data, limit)
  33. page_data = paginator.get_page(page) # [<grade<1>,<garde2>]
  34. data_list = [model_to_dict(data) for data in page_data]
  35. data = {"code": 0, "msg": "查询成功", "data": data_list, "count": paginator.count}
  36. return JsonResponse(data)
  37. class PostView:
  38. # 实现新增接口的 视图模板类
  39. # (可选继承)
  40. def post(self, request):
  41. form = self.form_class(request.POST,files=request.FILES)
  42. # files=request.FILES 是为了将请求中的文件参数传递进来
  43. self.form = form # 传递进来的数据 添加到实例属性
  44. if form.is_valid(): # 如果form校验通过
  45. obj = form.save() # 保存到数据库
  46. self.instance = obj # 新增的这一条数据(表记录) 添加到实例属性
  47. return JsonResponse({"code": 0, "msg": "操作成功", "id": obj.id})
  48. return JsonResponse({"code": -1, "msg": form.errors.get_json_data()})
  49. # 优化前 返回form校验的错误信息
  50. # return JsonResponse({"code": -1, "msg": form.error_msg})
  51. # 优化后 返回格式化form错误信息
  52. # form,model
  53. class PutView:
  54. # 实现修改接口的 视图模板类
  55. # (可选继承)
  56. def put(self, request):
  57. id = str(request.PUT.get("id"))
  58. if not id:
  59. return JsonResponse({"code": -1, "msg": "请传入要修改的id"})
  60. if not id.isdigit():
  61. return JsonResponse({"code": -1, "msg": "id是数字"})
  62. query_set = self.model_class.objects.filter(id=id)
  63. if not query_set.exists():
  64. return JsonResponse({"code": -1, "msg": "要修改的id不存在"})
  65. grade = query_set.first()
  66. form = self.form_class(request.PUT, instance=grade,files=request.FILES)
  67. # files=request.FILES 是为了将请求中的文件参数传递进来
  68. self.form = form
  69. self.instance = query_set.first()
  70. if form.is_valid():
  71. obj = form.save() # 保存到数据库
  72. return JsonResponse({"code": 0, "msg": "操作成功", "id": obj.id})
  73. return JsonResponse({"code": -1, "msg": form.errors.get_json_data()})
  74. # model Grade
  75. class DeleteView:
  76. # 实现删除接口的 视图模板类
  77. # (可选继承)
  78. def delete(self, request):
  79. id = str(request.GET.get("id"))
  80. if not id:
  81. return JsonResponse({"code": -1, "msg": "请传入要修改的id"})
  82. if not id.isdigit():
  83. return JsonResponse({"code": -1, "msg": "id是数字"})
  84. query_set = self.model_class.objects.filter(id=id)
  85. self.instance = query_set.first()
  86. if not query_set.exists():
  87. return JsonResponse({"code": -1, "msg": "要修改的id不存在"})
  88. query_set.delete()
  89. return JsonResponse({"code": 0, "msg": "删除成功!"})
  90. class ThzView(BaseView,PutView,PostView,GetView,DeleteView):
  91. # 继承了(基类、增删改查类)
  92. # 实现了增删改查接口的 视图模板类
  93. # (可选继承)
  94. pass

2.3、视图函数按需继承视图模板类

应用视图文件中,编写视图函数,开发接口

  1. from common.custom_class import ThzView
  2. # 从公共文件夹下的 公共类文件里 导入视图配置的类
  3. class StudentView(ThzView):# 实现了学生信息增删改查功能的接口
  4. # 继承这个 视图模板类
  5. search_fields = ["name", "phone"]
  6. # 指定哪些字段支持模糊查询
  7. filter_fields = ["id","grade"]
  8. # 指定哪些字段支持精确查询
  9. form_class = forms.StudentForm
  10. # 指定校验的form类
  11. model_class = models.Student
  12. # 指定model模型类(接口要操作的数据表)
  13. class GradeView(BaseView,GetView,PostView):# 实现了班级信息 查询/新增功能的接口
  14. # 按需继承 基类、查询、新增功能的类
  15. search_fields = ["name", "desc"]
  16. filter_fields = ["id"]
  17. form_class = forms.GradeForm
  18. model_class = models.Grade

3、视图模板文件再优化(格式化form错误信息)

  • 新建一个公共代码文件夹 common 文件夹
  • 在 common 文件夹中新建一个公共工具 utils.py文件(名字自定义即可);
  • 在这个文件中定义一个实现格式化form错误信息类(类名自定义即可)。

    3.1、优化后优点

  • 在需要返回form校验后的出错信息,不用在使用 form.errors.get_json_data() 了;

  • 直接使用 form.error_msg 即可(将多条错误信息合并成一条信息输出,更简洁);

3.2、格式化错误信息的类源码

  1. class FormatFormError:
  2. # 格式化form错误信息
  3. # 用来简化 调用forms校验出错信息 的类
  4. # 需要在forms 的类中继承这个类
  5. @property # 属性方法(可以不加括号调用)
  6. def error_msg(self):
  7. error_msg_list = []
  8. error_msg_dict = self.errors.get_json_data()
  9. for k,v in error_msg_dict.items():
  10. error_dic = v[0]
  11. msg = error_dic.get("message")
  12. msg = k + msg
  13. error_msg_list.append(msg)
  14. return " ".join(error_msg_list)
  15. #将多条错误信息合并成一条信息输出,更简洁

3.3、使用方法

需要在forms.py文件的类中继承这个类

  1. from . import models
  2. from django import forms
  3. from common.utils import FormatFormError
  4. # 如果form对应了一个model
  5. class GradeForm(forms.ModelForm,FormatFormError):# 继承FormatFormError这个类
  6. # password2 = forms.CharField(min_length=6,max_length=13)
  7. # 数据库表中没有的字段,业务上需要校验的字段,可以在这里定义,和普通的form一样
  8. class Meta:
  9. model = models.Grade
  10. fields = "__all__" # 校验表里面所有字段
  11. # fields = ["name",""] # 校验表里面哪些字段
  12. # exclude = [] # 不校验表里哪些字段
  13. # 如果字段需要单独校验,也可以像普通的form一样 单独 用clean_xxx 去校验
  14. # def clean_name(self):
  15. # name = self.cleaned_data["name"]
  16. # if not name.startswith("班级"):
  17. # raise forms.ValidationError("班级名需要以“班级”开头")
  18. # return name
  19. class StudentForm(forms.ModelForm,FormatFormError):# 继承FormatFormError这个类
  20. class Meta:
  21. model = models.Student
  22. fields = "__all__"

继承后,这个表单验证的类 多了一个error_msg方法,后面再需要返回form的错误信息时,
直接使用 form.error_msg 即可(将多条错误信息合并成一条信息输出,更简洁)

视图模板类(优化版)源码中使用

在视图模板类中的 PostView 实现新增接口的 视图模板类,使用 格式化form错误信息

  1. from django.views import View
  2. from django.core.paginator import Paginator
  3. from django.db.models import Q
  4. from django.http.response import JsonResponse
  5. from .utils import model_to_dict
  6. class BaseView(View):
  7. # 接口视图模板的基类
  8. #(必须继承的)
  9. search_fields = [] # 指定哪些字段支持模糊查询
  10. filter_fields = [] # 指定哪些字段支持精确查询
  11. form_class = None # 指定的form(forms校验 类)
  12. model_class = None # 指定的model(模型类)
  13. class GetView:
  14. # 实现查询接口的 视图模板类(支持分页、模糊/精确查询)
  15. # (可选继承)
  16. def get(self, request):
  17. limit = request.GET.get("limit", 10) # 每页多少条数据
  18. page = request.GET.get("page", 1) # 第几页
  19. search = request.GET.get("search") # 模糊查询的内容
  20. query_dict = {} # {id:1,name:xxx}
  21. q = Q() # None
  22. for field in self.filter_fields:
  23. value = request.GET.get(field)
  24. if value != None:
  25. query_dict[field] = value
  26. if search:
  27. for field in self.search_fields:
  28. d = {"%s__contains" % field: search}
  29. q = q | Q(**d)
  30. all_data = self.model_class.objects.filter(**query_dict).filter(q)
  31. # 先精确,后模糊
  32. paginator = Paginator(all_data, limit)
  33. page_data = paginator.get_page(page) # [<grade<1>,<garde2>]
  34. data_list = [model_to_dict(data) for data in page_data]
  35. data = {"code": 0, "msg": "查询成功", "data": data_list, "count": paginator.count}
  36. return JsonResponse(data)
  37. class PostView:
  38. # 实现新增接口的 视图模板类
  39. # (可选继承)
  40. def post(self, request):
  41. form = self.form_class(request.POST,files=request.FILES)
  42. # files=request.FILES 是为了将请求中的文件参数传递进来
  43. self.form = form # 传递进来的数据 添加到实例属性
  44. if form.is_valid(): # 如果form校验通过
  45. obj = form.save() # 保存到数据库
  46. self.instance = obj # 新增的这一条数据(表记录) 添加到实例属性
  47. return JsonResponse({"code": 0, "msg": "操作成功", "id": obj.id})
  48. # return JsonResponse({"code": -1, "msg": form.errors.get_json_data()})
  49. # (优化前的 返回form错误信息)
  50. return JsonResponse({"code": -1, "msg": form.error_msg})
  51. # (优化后的 返回form错误信息)
  52. # (看这里!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)
  53. # 返回格式化form错误信息!!!!!!!!!!!!!!!!!!!!!!!
  54. class PutView:
  55. # 实现修改接口的 视图模板类
  56. # (可选继承)
  57. def put(self, request):
  58. id = str(request.PUT.get("id"))
  59. if not id:
  60. return JsonResponse({"code": -1, "msg": "请传入要修改的id"})
  61. if not id.isdigit():
  62. return JsonResponse({"code": -1, "msg": "id是数字"})
  63. query_set = self.model_class.objects.filter(id=id)
  64. if not query_set.exists():
  65. return JsonResponse({"code": -1, "msg": "要修改的id不存在"})
  66. grade = query_set.first()
  67. form = self.form_class(request.PUT, instance=grade,files=request.FILES)
  68. # files=request.FILES 是为了将请求中的文件参数传递进来
  69. self.form = form
  70. self.instance = query_set.first()
  71. if form.is_valid():
  72. obj = form.save() # 保存到数据库
  73. return JsonResponse({"code": 0, "msg": "操作成功", "id": obj.id})
  74. #return JsonResponse({"code": -1, "msg": form.errors.get_json_data()})
  75. # (优化前的 返回form错误信息)
  76. return JsonResponse({"code": -1, "msg": form.error_msg})
  77. # (优化后的 返回form错误信息)
  78. # (看这里!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)
  79. # 返回格式化form错误信息!!!!!!!!!!!!!!!!!!!!!!!
  80. # model Grade
  81. class DeleteView:
  82. # 实现删除接口的 视图模板类
  83. # (可选继承)
  84. def delete(self, request):
  85. id = str(request.GET.get("id"))
  86. if not id:
  87. return JsonResponse({"code": -1, "msg": "请传入要修改的id"})
  88. if not id.isdigit():
  89. return JsonResponse({"code": -1, "msg": "id是数字"})
  90. query_set = self.model_class.objects.filter(id=id)
  91. self.instance = query_set.first()
  92. if not query_set.exists():
  93. return JsonResponse({"code": -1, "msg": "要修改的id不存在"})
  94. query_set.delete()
  95. return JsonResponse({"code": 0, "msg": "删除成功!"})
  96. class ThzView(BaseView,PutView,PostView,GetView,DeleteView):
  97. # 继承了(基类、增删改查类)
  98. # 实现了增删改查接口的 视图模板类
  99. # (可选继承)
  100. pass

4、视图模板文件再优化(优化JsonResponse)

4.1、优化后优点

  • 每次返回响应不用再单独写一个字典了,例如 return JsonResponse({“code”: 0, “msg”: “删除成功!”})
  • 简化代码

4.2、优化JsonResponse 的源码

  1. from django.http.response import JsonResponse
  2. # 优化JsonResponse的函数
  3. # 优化后,返回响应时 不用每次定义一个字典了
  4. def ThzResponse(code=0, msg="操作成功", **kwargs):
  5. data = {"code": code, "msg": msg}
  6. data.update(kwargs)
  7. return JsonResponse(data, json_dumps_params={"ensure_ascii": False})

4.3、视图模板类中使用

  1. from django.views import View
  2. from django.core.paginator import Paginator
  3. from django.db.models import Q
  4. from common.utils import model_to_dict,ThzResponse # 导入优化后的JsonResponse
  5. class BaseView(View):
  6. search_fields = [] # 指定哪些字段支持模糊查询
  7. filter_fields = []
  8. form_class = None # 指定的form
  9. model_class = None # 指定的model
  10. class GetView:
  11. def get(self, request):
  12. limit = request.GET.get("limit", 10)
  13. page = request.GET.get("page", 1)
  14. search = request.GET.get("search")
  15. query_dict = {} # {id:1,name:xxx}
  16. q = Q() # None
  17. for field in self.filter_fields:
  18. value = request.GET.get(field)
  19. if value != None:
  20. query_dict[field] = value
  21. if search:
  22. for field in self.search_fields:
  23. d = {"%s__contains" % field: search}
  24. q = q | Q(**d)
  25. all_data = self.model_class.objects.filter(**query_dict).filter(q) # 先精确,后模糊
  26. paginator = Paginator(all_data, limit)
  27. page_data = paginator.get_page(page) # [<grade<1>,<garde2>]
  28. data_list = [model_to_dict(data) for data in page_data]
  29. return ThzResponse(data=data_list,count=paginator.count)
  30. # 优化后,返回响应时 不用每次定义一个字典了
  31. class PostView:
  32. def post(self, request):
  33. form = self.form_class(request.POST,files=request.FILES)
  34. # files=request.FILES 是为了将请求中的文件参数传递进来
  35. self.form = form
  36. if form.is_valid(): #false
  37. obj = form.save() # 保存到数据库
  38. self.instance = obj #新增的这一条数据
  39. return ThzResponse(id=obj.id)
  40. # 优化后,返回响应时 不用每次定义一个字典了
  41. return ThzResponse(-1,form.error_msg)
  42. # 优化后,返回响应时 不用每次定义一个字典了
  43. # form,model
  44. class PutView:
  45. def put(self, request):
  46. id = str(request.PUT.get("id"))
  47. if not id:
  48. return ThzResponse(-1,"请传入要修改的id")
  49. # 优化后,返回响应时 不用每次定义一个字典了
  50. if not id.isdigit():
  51. return ThzResponse(-1,"id是数字")
  52. # 优化后,返回响应时 不用每次定义一个字典了
  53. query_set = self.model_class.objects.filter(id=id)
  54. if not query_set.exists():
  55. return ThzResponse(-1, "要修改的id不存在")
  56. # 优化后,返回响应时 不用每次定义一个字典了
  57. grade = query_set.first()
  58. form = self.form_class(request.PUT, instance=grade,files=request.FILES)
  59. # files=request.FILES 是为了将请求中的文件参数传递进来
  60. self.form = form
  61. self.instance = query_set.first()
  62. if form.is_valid():
  63. obj = form.save() # 保存到数据库
  64. return ThzResponse(id=obj.id)
  65. return ThzResponse(-1,form.error_msg)
  66. # 优化后,返回响应时 不用每次定义一个字典了
  67. # model Grade
  68. class DeleteView:
  69. def delete(self, request):
  70. id = str(request.GET.get("id"))
  71. if not id:
  72. return ThzResponse(-1,"请传入要修改的id")
  73. # 优化后,返回响应时 不用每次定义一个字典了
  74. if not id.isdigit():
  75. return ThzResponse(-1,"id是数字")
  76. # 优化后,返回响应时 不用每次定义一个字典了
  77. query_set = self.model_class.objects.filter(id=id)
  78. self.instance = query_set.first()
  79. if not query_set.exists():
  80. return ThzResponse(-1, "要修改的id不存在")
  81. # 优化后,返回响应时 不用每次定义一个字典了
  82. query_set.delete()
  83. return ThzResponse()
  84. # 优化后,返回响应时 不用每次定义一个字典了
  85. class ThzView(BaseView,PutView,PostView,GetView,DeleteView):
  86. pass