#前言
为什么要配置一个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 View
from django.core.paginator import Paginator
from django.db.models import Q
from django.http.response import JsonResponse
from common.utils import model_to_dict # 导入自定义函数 model_to_dict
class 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() # None
for field in self.filter_fields:
value = request.GET.get(field)
if value != None:
query_dict[field] = value
if 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,model
def 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 Grade
def 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.GradeForm
model_class = models.Grade
2、视图模板文件优化(优化版本)
2.1、视图模板类 的优点:
- 接口开发更加简便,不用单独编写增删改查接口;
- 在对应应用下的 views.py 文件中编写接口视图函数时,直接继承 视图模板类 就可以了
- 继承 视图模板类 后,这个视图函数(接口)实现了增删改查(POST、DELETE、PUT、GET)功能
- 将模板视图的功能拆分,实现了按需继承(增删改查功能可单独配置)
2.2、视图模板类(优化版)源码
from django.views import View
from django.core.paginator import Paginator
from django.db.models import Q
from django.http.response import JsonResponse
from .utils import model_to_dict
class 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() # None
for field in self.filter_fields:
value = request.GET.get(field)
if value != None:
query_dict[field] = value
if 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,model
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 = form
self.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 Grade
class 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.GradeForm
model_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 + msg
error_msg_list.append(msg)
return " ".join(error_msg_list)
#将多条错误信息合并成一条信息输出,更简洁
3.3、使用方法
需要在forms.py文件的类中继承这个类
from . import models
from django import forms
from common.utils import FormatFormError
# 如果form对应了一个model
class GradeForm(forms.ModelForm,FormatFormError):# 继承FormatFormError这个类
# password2 = forms.CharField(min_length=6,max_length=13)
# 数据库表中没有的字段,业务上需要校验的字段,可以在这里定义,和普通的form一样
class Meta:
model = models.Grade
fields = "__all__" # 校验表里面所有字段
# fields = ["name",""] # 校验表里面哪些字段
# exclude = [] # 不校验表里哪些字段
# 如果字段需要单独校验,也可以像普通的form一样 单独 用clean_xxx 去校验
# def clean_name(self):
# name = self.cleaned_data["name"]
# if not name.startswith("班级"):
# raise forms.ValidationError("班级名需要以“班级”开头")
# return name
class StudentForm(forms.ModelForm,FormatFormError):# 继承FormatFormError这个类
class Meta:
model = models.Student
fields = "__all__"
继承后,这个表单验证的类 多了一个error_msg方法,后面再需要返回form的错误信息时,
直接使用 form.error_msg 即可(将多条错误信息合并成一条信息输出,更简洁)
视图模板类(优化版)源码中使用
在视图模板类中的 PostView 实现新增接口的 视图模板类,使用 格式化form错误信息
from django.views import View
from django.core.paginator import Paginator
from django.db.models import Q
from django.http.response import JsonResponse
from .utils import model_to_dict
class 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() # None
for field in self.filter_fields:
value = request.GET.get(field)
if value != None:
query_dict[field] = value
if 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 = form
self.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 Grade
class 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 View
from django.core.paginator import Paginator
from django.db.models import Q
from common.utils import model_to_dict,ThzResponse # 导入优化后的JsonResponse
class BaseView(View):
search_fields = [] # 指定哪些字段支持模糊查询
filter_fields = []
form_class = None # 指定的form
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() # None
for field in self.filter_fields:
value = request.GET.get(field)
if value != None:
query_dict[field] = value
if 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 = form
if form.is_valid(): #false
obj = form.save() # 保存到数据库
self.instance = obj #新增的这一条数据
return ThzResponse(id=obj.id)
# 优化后,返回响应时 不用每次定义一个字典了
return ThzResponse(-1,form.error_msg)
# 优化后,返回响应时 不用每次定义一个字典了
# form,model
class 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 = form
self.instance = query_set.first()
if form.is_valid():
obj = form.save() # 保存到数据库
return ThzResponse(id=obj.id)
return ThzResponse(-1,form.error_msg)
# 优化后,返回响应时 不用每次定义一个字典了
# model Grade
class 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