1、FBV与CBV简介
FBV:Function Based View(基于函数的view)
就是在视图里使用函数处理请求。
CBV:Class Based View(基于类的view)
就是在视图里使用类处理请求。
我们之前写过的都是基于函数的view,就叫FBV。还可以把view写成基于类的,那就是CBV。
1.1、FBV基于函数的视图
路由配置:
urlpatterns = [
path("login/", views.login),
]
from django.shortcuts import render,HttpResponse
def login(request):
if request.method == "GET":
return HttpResponse("GET 方法")
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd")
if user == "runoob" and pwd == "123456":
return HttpResponse("POST 方法")
else:
return HttpResponse("POST 方法1")
如果我们在浏览器中直接访问 http://127.0.0.1:8000/login/ ,输出结果为:
1.2、CBV基于类的视图
基于类的视图,就是使用了类来处理用户的请求,不同的请求我们可以在类中使用不同方法来处理,这样大大的提高了代码的可读性。
定义的类要继承父类 View,所以需要先引入库:
from django.views import View
执行对应请求的方法前会优先执行 dispatch 方法(在get/post/put…方法前执行),dispatch() 方法会根据请求的不同调用相应的方法来处理。
其实,在我们前面学到的知识都知道 Django 的 url 是将一个请求分配给可调用的函数的,而不是一个类,那是如何实现基于类的视图的呢? 主要还是通过父类 View 提供的一个静态方法 as_view() ,as_view 方法是基于类的外部接口, 他返回一个视图函数,调用后请求会传递给 dispatch 方法,dispatch 方法再根据不同请求来处理不同的方法。
路由配置:
urlpatterns = [
path("login/", views.Login.as_view()),
# as_view()方法绑定路由和 基于类的视图CBV
]
from django.shortcuts import render,HttpResponse
from django.views import View
class Login(View):
def get(self,request):
return HttpResponse("GET 方法")
def post(self,request):
user = request.POST.get("user")
pwd = request.POST.get("pwd")
if user == "runoob" and pwd == "123456":
return HttpResponse("POST 方法")
else:
return HttpResponse("POST 方法 1")
如果我们在浏览器中直接访问 http://127.0.0.1:8000/login/ ,输出结果为:
2、CVB基于类的视图-实现增删改查
这个应用的models.py
from django.db import models
# Create your models here.
class BaseModel(models.Model): # 基类
update_time = models.DateTimeField(auto_now=True)
create_time = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True # 说明这个类只是用来继承的。(就不会创建这个表了)
# 定义一个 班级表 模型类
class Grade(BaseModel): # 继承这个基类
name = models.CharField(verbose_name="班级", max_length=30, unique=True)
desc = models.CharField(verbose_name="班级描述", max_length=50, null=True, blank=True)
def __str__(self):
return self.name
# 定义一个 学生表 模型类
class Student(BaseModel): # 继承这个基类
name = models.CharField(max_length=30, verbose_name="姓名")
phone = models.CharField(max_length=11, verbose_name="手机号", unique=True)
qq = models.CharField(max_length=11, verbose_name="qq", unique=True)
grade = models.ForeignKey(Grade, on_delete=models.CASCADE)
def __str__(self):
return self.name
这个应用的forms.py
from . import models
from django import forms # 导入forms
# 如果form对应了一个model
class GradeForm(forms.ModelForm):
# 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
2.1、实现增加表记录-POST接口
from django.core.paginator import Paginator
from django.forms import model_to_dict
from django.shortcuts import render
from django.views import View
from django.http.response import JsonResponse
from django.db.models import Q
from . import forms, models
class GradeView(View):
# 用于给班级表新增记录
def post(self, request):
form = forms.GradeForm(request.POST)#把请求参数传递给 表单验证
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的校验信息
注意:
别忘了把这个基于类的视图绑定好路由
2.2、实现修改表记录-PUT接口
Django暂不支持PUT请求,获取不到PUT请求传递过来的参数
先定义一个中间件
用来解决PUT请求参数接收不到的问题
from django.http import QueryDict
from django.middleware.common import MiddlewareMixin
class PutMiddleware(MiddlewareMixin):
"""
给 Django 的request对象 增加 一个 PUT 对象
"""
def process_request(self, request):
if request.method.upper() == "PUT":
if "multipart" in request.content_type: # form-data
# 上面这种是能传文件的那种form
data, files = request.parse_file_upload(request.META, request)
request.PUT = data
request._files = files
else:
data = QueryDict(request.body) # 这种是把普通k-v传参的转成字典
request.PUT = data
编写视图函数
- 先确定修改哪条记录
- 然后再修改 ```python from django.core.paginator import Paginator from django.forms import model_to_dict from django.shortcuts import render from django.views import View from django.http.response import JsonResponse from django.db.models import Q from . import forms, models
class GradeView(View):
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 = models.Grade.objects.filter(id=id)
if not query_set.exists():
return JsonResponse({"code": -1, "msg": "要修改的id不存在"})
grade = query_set.first() # 定义的Grade 模型类的一个实例对象(就是表中的一条记录)
form = forms.GradeForm(request.PUT, instance=grade) # 加入instance=模型类实例对象, 表明本次是修改记录,不是新增记录
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()})
**接口工具调用一下接口,POST请求,修改记录**<br />![1647408073.png](https://cdn.nlark.com/yuque/0/2022/png/22480740/1647408076674-c4e25935-e84f-4d28-bff6-4dd42e9d553b.png#clientId=ua67573a3-9567-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=368&id=ue77edbb2&margin=%5Bobject%20Object%5D&name=1647408073.png&originHeight=460&originWidth=1369&originalType=binary&ratio=1&rotation=0&showTitle=false&size=40755&status=done&style=none&taskId=u697b0450-2003-44c8-a02a-4741ae6c50b&title=&width=1095.2)<br />![1647408180(1).png](https://cdn.nlark.com/yuque/0/2022/png/22480740/1647408184424-a2e4906f-1635-4ccf-8152-170ebada3318.png#clientId=ua67573a3-9567-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=190&id=ud52a9460&margin=%5Bobject%20Object%5D&name=1647408180%281%29.png&originHeight=238&originWidth=878&originalType=binary&ratio=1&rotation=0&showTitle=false&size=52010&status=done&style=none&taskId=ue53799e7-bd74-44ad-a814-d435593de2d&title=&width=702.4)
<a name="szXN3"></a>
## 2.3、实现删除表记录-DELETE接口
因为DELETE请求不带参数,只能在url中通过 查询字符串来传参,确定删除哪条记录
```python
from django.core.paginator import Paginator
from django.forms import model_to_dict
from django.shortcuts import render
from django.views import View
from django.http.response import JsonResponse
from django.db.models import Q
from . import forms, models
class GradeVies(View):
def delete(self, request):
id = request.GET.get("id")
# 因为DELETE请求不带参数,只能在url中通过 查询字符串来传参,确定删除哪条记录
if not id:
return JsonResponse({"code": -1, "msg": "请传入要修改的id"})
if not id.isdigit():
return JsonResponse({"code": -1, "msg": "id是数字"})
query_set = models.Grade.objects.filter(id=id)
if not query_set.exists():
return JsonResponse({"code": -1, "msg": "要修改的id不存在"})
query_set.delete()
return JsonResponse({"code": 0, "msg": "删除成功!"})
2.5、实现查询表记录-GET接口请求
- 查询所有的数据 -> 分页
- 查询单条数据
- 模糊查询 -> 分页
- 筛选查询
用来实现灵活配置的模糊查询,支持分页
from django.core.paginator import Paginator
from django.forms import model_to_dict
from django.shortcuts import render
from django.views import View
from django.http.response import JsonResponse
from django.db.models import Q
from . import forms, models
class GradeView(View):
#用于实现模糊查询 方式1 新增需要模糊匹配的字段时 需要改代码
# def get(self, request):
# """
# 1、查询所有的数据 -》 分页
# 2、查询单条数据
# 3、模糊查询 -》分页
# 4、筛选
# """
# limit = request.GET.get("limit", 10)
# page = request.GET.get("page", 1)
# search = request.GET.get("search", )
# if search:
# all_data = models.Grade.objects.filter(Q(name__contains=search) | Q(desc__contains=search))
# else:
# all_data = models.Grade.objects.all()
#
#
# # all_data = models.Grade.objects.all()
# 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)
# 方式2 模糊查询,灵活配置的,不需要改代码,
search_fields = ["name", "desc"] # 指定哪些字段支持模糊查询
def get(self, request):
limit = request.GET.get("limit", 10)
page = request.GET.get("page", 1)
search = request.GET.get("search", )
if search:
q = Q() # None
for field in self.search_fields:
d = {"%s__contains" % field: search}
q = q | Q(**d)
# all_data = models.Grade.objects.filter( Q(name__contains=search) | Q(desc__contains=search) )
all_data = models.Grade.objects.filter(q)
else:
all_data = models.Grade.objects.all()
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 GradeView(View):
search_fields = ["name", "desc"] # 指定哪些字段支持模糊查询
filter_fields = ["id", "name"]
# model Grade
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 = models.Grade.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)
参考博客
菜鸟教程:Django 视图 - FBV 与 CBV
https://www.runoob.com/django/django-views-fbv-cbv.html
博客园:Django 视图之FBV与CBV
https://www.cnblogs.com/Michael—chen/p/10952134.html