#前言
为什么要配置一个view模板(视图模板)?
- 接口开发更加简便,不用单独编写增删改查接口的视图;
- 在对应应用下的 views.py 文件中编写接口视图函数时,直接继承 视图模板类 就可以了
- 继承 视图模板类 后,这个视图函数(接口)实现了增删改查(POST、DELETE、PUT、GET)功能
1、视图模板文件配置(基础版本)
- 新建一个公共代码文件夹 common 文件夹
- 在 common 文件夹中新建一个公共的视图模板custom_class.py文件(名字自定义即可);
- 在这个文件中定义一个公共的视图模板类(类名自定义即可)。
1.1、视图模板类 的优点:
- 接口开发更加简便,不用单独编写增删改查接口;
- 在对应应用下的 views.py 文件中编写接口视图函数时,直接继承 视图模板类 就可以了
- 继承 视图模板类 后,这个视图函数(接口)实现了增删改查(POST、DELETE、PUT、GET)功能
1.2、视图模板类源码
from django.views import Viewfrom django.core.paginator import Paginatorfrom django.db.models import Qfrom django.http.response import JsonResponsefrom common.utils import model_to_dict # 导入自定义函数 model_to_dictclass ThzView(View):# 实现(增删改查)接口的 视图模板类(支持分页、模糊/精确查询)search_fields = [] # 指定哪些字段支持模糊查询filter_fields = [] # 指定哪些字段支持精确查询form_class = None # 指定的form 类model_class = None # 指定的model类def get(self, request):# 实现查询数据功能的 视图模板方法(支持分页、模糊/精确查询)limit = request.GET.get("limit", 10)page = request.GET.get("page", 1)search = request.GET.get("search")query_dict = {} # {id:1,name:xxx}q = Q() # Nonefor field in self.filter_fields:value = request.GET.get(field)if value != None:query_dict[field] = valueif search:for field in self.search_fields:d = {"%s__contains" % field: search}q = q | Q(**d)# all_data = models.Grade.objects.filter(q).filter(**query_dict) #先模糊,后精确all_data = self.model_class.objects.filter(**query_dict).filter(q) # 先精确,后模糊paginator = Paginator(all_data, limit)page_data = paginator.get_page(page) # [<grade<1>,<garde2>]data_list = [model_to_dict(data) for data in page_data]data = {"code": 0, "msg": "查询成功", "data": data_list, "count": paginator.count}return JsonResponse(data)def post(self, request):# 实现新增数据功能的 视图模板方法form = self.form_class(request.POST,files=request.FILES)# files=request.FILES 是为了将请求中的文件参数传递进来if form.is_valid():obj = form.save() # 保存到数据库return JsonResponse({"code": 0, "msg": "操作成功", "id": obj.id})return JsonResponse({"code": -1, "msg": form.errors.get_json_data()})# form,modeldef put(self, request):# 实现修改数据功能的 视图模板方法id = request.PUT.get("id")if not id:return JsonResponse({"code": -1, "msg": "请传入要修改的id"})if not id.isdigit():return JsonResponse({"code": -1, "msg": "id是数字"})query_set = self.model_class.objects.filter(id=id)if not query_set.exists():return JsonResponse({"code": -1, "msg": "要修改的id不存在"})grade = query_set.first()form = self.form_class(request.PUT, instance=grade,files=request.FILES)# files=request.FILES 是为了将请求中的文件参数传递进来if form.is_valid():obj = form.save() # 保存到数据库return JsonResponse({"code": 0, "msg": "操作成功", "id": obj.id})return JsonResponse({"code": -1, "msg": form.errors.get_json_data()})# model Gradedef delete(self, request):# 实现删除数据功能的 视图模板方法id = request.GET.get("id")if not id:return JsonResponse({"code": -1, "msg": "请传入要修改的id"})if not id.isdigit():return JsonResponse({"code": -1, "msg": "id是数字"})query_set = self.model_class.objects.filter(id=id)if not query_set.exists():return JsonResponse({"code": -1, "msg": "要修改的id不存在"})query_set.delete()return JsonResponse({"code": 0, "msg": "删除成功!"})
1.3、视图函数继承视图模板类
- 使用CBV:Class Based View(基于类的视图)开发
- 在 CBV 视图类中继承视图模板类即可
- 继承后,这个视图拥有了视图模板类的 增删改查功能
应用视图文件中,编写视图函数,开发接口
from common.custom_class import ThzView# 从公共文件夹下的 公共类文件里 导入视图模板类class StudentView(ThzView): # 实现了学生信息增删改查功能的接口# 继承这个 视图模板类search_fields = ["name", "phone"]# 指定哪些字段支持模糊查询filter_fields = ["id","grade"]# 指定哪些字段支持精确查询form_class = forms.StudentForm# 指定校验的form类model_class = models.Student# 指定model模型类(接口要操作的数据表)class GradeView(ThzView): # 实现了班级信息增删改查功能的接口search_fields = ["name", "desc"]filter_fields = ["id"]form_class = forms.GradeFormmodel_class = models.Grade
2、视图模板文件优化(优化版本)
2.1、视图模板类 的优点:
- 接口开发更加简便,不用单独编写增删改查接口;
- 在对应应用下的 views.py 文件中编写接口视图函数时,直接继承 视图模板类 就可以了
- 继承 视图模板类 后,这个视图函数(接口)实现了增删改查(POST、DELETE、PUT、GET)功能
- 将模板视图的功能拆分,实现了按需继承(增删改查功能可单独配置)
2.2、视图模板类(优化版)源码
from django.views import Viewfrom django.core.paginator import Paginatorfrom django.db.models import Qfrom django.http.response import JsonResponsefrom .utils import model_to_dictclass BaseView(View):# 接口视图模板的基类#(必须继承的)search_fields = [] # 指定哪些字段支持模糊查询filter_fields = [] # 指定哪些字段支持精确查询form_class = None # 指定的form(forms校验 类)model_class = None # 指定的model(模型类)class GetView:# 实现查询接口的 视图模板类(支持分页、模糊/精确查询)# (可选继承)def get(self, request):limit = request.GET.get("limit", 10) # 每页多少条数据page = request.GET.get("page", 1) # 第几页search = request.GET.get("search") # 模糊查询的内容query_dict = {} # {id:1,name:xxx}q = Q() # Nonefor field in self.filter_fields:value = request.GET.get(field)if value != None:query_dict[field] = valueif search:for field in self.search_fields:d = {"%s__contains" % field: search}q = q | Q(**d)all_data = self.model_class.objects.filter(**query_dict).filter(q)# 先精确,后模糊paginator = Paginator(all_data, limit)page_data = paginator.get_page(page) # [<grade<1>,<garde2>]data_list = [model_to_dict(data) for data in page_data]data = {"code": 0, "msg": "查询成功", "data": data_list, "count": paginator.count}return JsonResponse(data)class PostView:# 实现新增接口的 视图模板类# (可选继承)def post(self, request):form = self.form_class(request.POST,files=request.FILES)# files=request.FILES 是为了将请求中的文件参数传递进来self.form = form # 传递进来的数据 添加到实例属性if form.is_valid(): # 如果form校验通过obj = form.save() # 保存到数据库self.instance = obj # 新增的这一条数据(表记录) 添加到实例属性return JsonResponse({"code": 0, "msg": "操作成功", "id": obj.id})return JsonResponse({"code": -1, "msg": form.errors.get_json_data()})# 优化前 返回form校验的错误信息# return JsonResponse({"code": -1, "msg": form.error_msg})# 优化后 返回格式化form错误信息# form,modelclass PutView:# 实现修改接口的 视图模板类# (可选继承)def put(self, request):id = str(request.PUT.get("id"))if not id:return JsonResponse({"code": -1, "msg": "请传入要修改的id"})if not id.isdigit():return JsonResponse({"code": -1, "msg": "id是数字"})query_set = self.model_class.objects.filter(id=id)if not query_set.exists():return JsonResponse({"code": -1, "msg": "要修改的id不存在"})grade = query_set.first()form = self.form_class(request.PUT, instance=grade,files=request.FILES)# files=request.FILES 是为了将请求中的文件参数传递进来self.form = formself.instance = query_set.first()if form.is_valid():obj = form.save() # 保存到数据库return JsonResponse({"code": 0, "msg": "操作成功", "id": obj.id})return JsonResponse({"code": -1, "msg": form.errors.get_json_data()})# model Gradeclass DeleteView:# 实现删除接口的 视图模板类# (可选继承)def delete(self, request):id = str(request.GET.get("id"))if not id:return JsonResponse({"code": -1, "msg": "请传入要修改的id"})if not id.isdigit():return JsonResponse({"code": -1, "msg": "id是数字"})query_set = self.model_class.objects.filter(id=id)self.instance = query_set.first()if not query_set.exists():return JsonResponse({"code": -1, "msg": "要修改的id不存在"})query_set.delete()return JsonResponse({"code": 0, "msg": "删除成功!"})class ThzView(BaseView,PutView,PostView,GetView,DeleteView):# 继承了(基类、增删改查类)# 实现了增删改查接口的 视图模板类# (可选继承)pass
2.3、视图函数按需继承视图模板类
应用视图文件中,编写视图函数,开发接口
from common.custom_class import ThzView# 从公共文件夹下的 公共类文件里 导入视图配置的类class StudentView(ThzView):# 实现了学生信息增删改查功能的接口# 继承这个 视图模板类search_fields = ["name", "phone"]# 指定哪些字段支持模糊查询filter_fields = ["id","grade"]# 指定哪些字段支持精确查询form_class = forms.StudentForm# 指定校验的form类model_class = models.Student# 指定model模型类(接口要操作的数据表)class GradeView(BaseView,GetView,PostView):# 实现了班级信息 查询/新增功能的接口# 按需继承 基类、查询、新增功能的类search_fields = ["name", "desc"]filter_fields = ["id"]form_class = forms.GradeFormmodel_class = models.Grade
3、视图模板文件再优化(格式化form错误信息)
- 新建一个公共代码文件夹 common 文件夹
- 在 common 文件夹中新建一个公共工具 utils.py文件(名字自定义即可);
在这个文件中定义一个实现格式化form错误信息类(类名自定义即可)。
3.1、优化后优点
在需要返回form校验后的出错信息,不用在使用 form.errors.get_json_data() 了;
- 直接使用 form.error_msg 即可(将多条错误信息合并成一条信息输出,更简洁);
3.2、格式化错误信息的类源码
class FormatFormError:# 格式化form错误信息# 用来简化 调用forms校验出错信息 的类# 需要在forms 的类中继承这个类@property # 属性方法(可以不加括号调用)def error_msg(self):error_msg_list = []error_msg_dict = self.errors.get_json_data()for k,v in error_msg_dict.items():error_dic = v[0]msg = error_dic.get("message")msg = k + msgerror_msg_list.append(msg)return " ".join(error_msg_list)#将多条错误信息合并成一条信息输出,更简洁
3.3、使用方法
需要在forms.py文件的类中继承这个类
from . import modelsfrom django import formsfrom common.utils import FormatFormError# 如果form对应了一个modelclass GradeForm(forms.ModelForm,FormatFormError):# 继承FormatFormError这个类# password2 = forms.CharField(min_length=6,max_length=13)# 数据库表中没有的字段,业务上需要校验的字段,可以在这里定义,和普通的form一样class Meta:model = models.Gradefields = "__all__" # 校验表里面所有字段# fields = ["name",""] # 校验表里面哪些字段# exclude = [] # 不校验表里哪些字段# 如果字段需要单独校验,也可以像普通的form一样 单独 用clean_xxx 去校验# def clean_name(self):# name = self.cleaned_data["name"]# if not name.startswith("班级"):# raise forms.ValidationError("班级名需要以“班级”开头")# return nameclass StudentForm(forms.ModelForm,FormatFormError):# 继承FormatFormError这个类class Meta:model = models.Studentfields = "__all__"
继承后,这个表单验证的类 多了一个error_msg方法,后面再需要返回form的错误信息时,
直接使用 form.error_msg 即可(将多条错误信息合并成一条信息输出,更简洁)
视图模板类(优化版)源码中使用
在视图模板类中的 PostView 实现新增接口的 视图模板类,使用 格式化form错误信息
from django.views import Viewfrom django.core.paginator import Paginatorfrom django.db.models import Qfrom django.http.response import JsonResponsefrom .utils import model_to_dictclass BaseView(View):# 接口视图模板的基类#(必须继承的)search_fields = [] # 指定哪些字段支持模糊查询filter_fields = [] # 指定哪些字段支持精确查询form_class = None # 指定的form(forms校验 类)model_class = None # 指定的model(模型类)class GetView:# 实现查询接口的 视图模板类(支持分页、模糊/精确查询)# (可选继承)def get(self, request):limit = request.GET.get("limit", 10) # 每页多少条数据page = request.GET.get("page", 1) # 第几页search = request.GET.get("search") # 模糊查询的内容query_dict = {} # {id:1,name:xxx}q = Q() # Nonefor field in self.filter_fields:value = request.GET.get(field)if value != None:query_dict[field] = valueif search:for field in self.search_fields:d = {"%s__contains" % field: search}q = q | Q(**d)all_data = self.model_class.objects.filter(**query_dict).filter(q)# 先精确,后模糊paginator = Paginator(all_data, limit)page_data = paginator.get_page(page) # [<grade<1>,<garde2>]data_list = [model_to_dict(data) for data in page_data]data = {"code": 0, "msg": "查询成功", "data": data_list, "count": paginator.count}return JsonResponse(data)class PostView:# 实现新增接口的 视图模板类# (可选继承)def post(self, request):form = self.form_class(request.POST,files=request.FILES)# files=request.FILES 是为了将请求中的文件参数传递进来self.form = form # 传递进来的数据 添加到实例属性if form.is_valid(): # 如果form校验通过obj = form.save() # 保存到数据库self.instance = obj # 新增的这一条数据(表记录) 添加到实例属性return JsonResponse({"code": 0, "msg": "操作成功", "id": obj.id})# return JsonResponse({"code": -1, "msg": form.errors.get_json_data()})# (优化前的 返回form错误信息)return JsonResponse({"code": -1, "msg": form.error_msg})# (优化后的 返回form错误信息)# (看这里!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)# 返回格式化form错误信息!!!!!!!!!!!!!!!!!!!!!!!class PutView:# 实现修改接口的 视图模板类# (可选继承)def put(self, request):id = str(request.PUT.get("id"))if not id:return JsonResponse({"code": -1, "msg": "请传入要修改的id"})if not id.isdigit():return JsonResponse({"code": -1, "msg": "id是数字"})query_set = self.model_class.objects.filter(id=id)if not query_set.exists():return JsonResponse({"code": -1, "msg": "要修改的id不存在"})grade = query_set.first()form = self.form_class(request.PUT, instance=grade,files=request.FILES)# files=request.FILES 是为了将请求中的文件参数传递进来self.form = formself.instance = query_set.first()if form.is_valid():obj = form.save() # 保存到数据库return JsonResponse({"code": 0, "msg": "操作成功", "id": obj.id})#return JsonResponse({"code": -1, "msg": form.errors.get_json_data()})# (优化前的 返回form错误信息)return JsonResponse({"code": -1, "msg": form.error_msg})# (优化后的 返回form错误信息)# (看这里!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)# 返回格式化form错误信息!!!!!!!!!!!!!!!!!!!!!!!# model Gradeclass DeleteView:# 实现删除接口的 视图模板类# (可选继承)def delete(self, request):id = str(request.GET.get("id"))if not id:return JsonResponse({"code": -1, "msg": "请传入要修改的id"})if not id.isdigit():return JsonResponse({"code": -1, "msg": "id是数字"})query_set = self.model_class.objects.filter(id=id)self.instance = query_set.first()if not query_set.exists():return JsonResponse({"code": -1, "msg": "要修改的id不存在"})query_set.delete()return JsonResponse({"code": 0, "msg": "删除成功!"})class ThzView(BaseView,PutView,PostView,GetView,DeleteView):# 继承了(基类、增删改查类)# 实现了增删改查接口的 视图模板类# (可选继承)pass
4、视图模板文件再优化(优化JsonResponse)
4.1、优化后优点
- 每次返回响应不用再单独写一个字典了,例如 return JsonResponse({“code”: 0, “msg”: “删除成功!”})
- 简化代码
4.2、优化JsonResponse 的源码
from django.http.response import JsonResponse# 优化JsonResponse的函数# 优化后,返回响应时 不用每次定义一个字典了def ThzResponse(code=0, msg="操作成功", **kwargs):data = {"code": code, "msg": msg}data.update(kwargs)return JsonResponse(data, json_dumps_params={"ensure_ascii": False})
4.3、视图模板类中使用
from django.views import Viewfrom django.core.paginator import Paginatorfrom django.db.models import Qfrom common.utils import model_to_dict,ThzResponse # 导入优化后的JsonResponseclass BaseView(View):search_fields = [] # 指定哪些字段支持模糊查询filter_fields = []form_class = None # 指定的formmodel_class = None # 指定的modelclass GetView:def get(self, request):limit = request.GET.get("limit", 10)page = request.GET.get("page", 1)search = request.GET.get("search")query_dict = {} # {id:1,name:xxx}q = Q() # Nonefor field in self.filter_fields:value = request.GET.get(field)if value != None:query_dict[field] = valueif search:for field in self.search_fields:d = {"%s__contains" % field: search}q = q | Q(**d)all_data = self.model_class.objects.filter(**query_dict).filter(q) # 先精确,后模糊paginator = Paginator(all_data, limit)page_data = paginator.get_page(page) # [<grade<1>,<garde2>]data_list = [model_to_dict(data) for data in page_data]return ThzResponse(data=data_list,count=paginator.count)# 优化后,返回响应时 不用每次定义一个字典了class PostView:def post(self, request):form = self.form_class(request.POST,files=request.FILES)# files=request.FILES 是为了将请求中的文件参数传递进来self.form = formif form.is_valid(): #falseobj = form.save() # 保存到数据库self.instance = obj #新增的这一条数据return ThzResponse(id=obj.id)# 优化后,返回响应时 不用每次定义一个字典了return ThzResponse(-1,form.error_msg)# 优化后,返回响应时 不用每次定义一个字典了# form,modelclass PutView:def put(self, request):id = str(request.PUT.get("id"))if not id:return ThzResponse(-1,"请传入要修改的id")# 优化后,返回响应时 不用每次定义一个字典了if not id.isdigit():return ThzResponse(-1,"id是数字")# 优化后,返回响应时 不用每次定义一个字典了query_set = self.model_class.objects.filter(id=id)if not query_set.exists():return ThzResponse(-1, "要修改的id不存在")# 优化后,返回响应时 不用每次定义一个字典了grade = query_set.first()form = self.form_class(request.PUT, instance=grade,files=request.FILES)# files=request.FILES 是为了将请求中的文件参数传递进来self.form = formself.instance = query_set.first()if form.is_valid():obj = form.save() # 保存到数据库return ThzResponse(id=obj.id)return ThzResponse(-1,form.error_msg)# 优化后,返回响应时 不用每次定义一个字典了# model Gradeclass DeleteView:def delete(self, request):id = str(request.GET.get("id"))if not id:return ThzResponse(-1,"请传入要修改的id")# 优化后,返回响应时 不用每次定义一个字典了if not id.isdigit():return ThzResponse(-1,"id是数字")# 优化后,返回响应时 不用每次定义一个字典了query_set = self.model_class.objects.filter(id=id)self.instance = query_set.first()if not query_set.exists():return ThzResponse(-1, "要修改的id不存在")# 优化后,返回响应时 不用每次定义一个字典了query_set.delete()return ThzResponse()# 优化后,返回响应时 不用每次定义一个字典了class ThzView(BaseView,PutView,PostView,GetView,DeleteView):pass
