1、FBV与CBV简介

FBV:Function Based View(基于函数的view)
就是在视图里使用函数处理请求。

CBV:Class Based View(基于类的view)
就是在视图里使用类处理请求。

我们之前写过的都是基于函数的view,就叫FBV。还可以把view写成基于类的,那就是CBV。

1.1、FBV基于函数的视图

路由配置:

  1. urlpatterns = [
  2. path("login/", views.login),
  3. ]
  1. from django.shortcuts import render,HttpResponse
  2. def login(request):
  3. if request.method == "GET":
  4. return HttpResponse("GET 方法")
  5. if request.method == "POST":
  6. user = request.POST.get("user")
  7. pwd = request.POST.get("pwd")
  8. if user == "runoob" and pwd == "123456":
  9. return HttpResponse("POST 方法")
  10. else:
  11. return HttpResponse("POST 方法1")

如果我们在浏览器中直接访问 http://127.0.0.1:8000/login/ ,输出结果为:
image.png

1.2、CBV基于类的视图

基于类的视图,就是使用了类来处理用户的请求,不同的请求我们可以在类中使用不同方法来处理,这样大大的提高了代码的可读性。
定义的类要继承父类 View,所以需要先引入库:

  1. from django.views import View

执行对应请求的方法前会优先执行 dispatch 方法(在get/post/put…方法前执行),dispatch() 方法会根据请求的不同调用相应的方法来处理。
其实,在我们前面学到的知识都知道 Django 的 url 是将一个请求分配给可调用的函数的,而不是一个类,那是如何实现基于类的视图的呢? 主要还是通过父类 View 提供的一个静态方法 as_view() ,as_view 方法是基于类的外部接口, 他返回一个视图函数,调用后请求会传递给 dispatch 方法,dispatch 方法再根据不同请求来处理不同的方法。

路由配置:

  1. urlpatterns = [
  2. path("login/", views.Login.as_view()),
  3. # as_view()方法绑定路由和 基于类的视图CBV
  4. ]
  1. from django.shortcuts import render,HttpResponse
  2. from django.views import View
  3. class Login(View):
  4. def get(self,request):
  5. return HttpResponse("GET 方法")
  6. def post(self,request):
  7. user = request.POST.get("user")
  8. pwd = request.POST.get("pwd")
  9. if user == "runoob" and pwd == "123456":
  10. return HttpResponse("POST 方法")
  11. else:
  12. return HttpResponse("POST 方法 1")

如果我们在浏览器中直接访问 http://127.0.0.1:8000/login/ ,输出结果为:
image.png

2、CVB基于类的视图-实现增删改查

这个应用的models.py

  1. from django.db import models
  2. # Create your models here.
  3. class BaseModel(models.Model): # 基类
  4. update_time = models.DateTimeField(auto_now=True)
  5. create_time = models.DateTimeField(auto_now_add=True)
  6. class Meta:
  7. abstract = True # 说明这个类只是用来继承的。(就不会创建这个表了)
  8. # 定义一个 班级表 模型类
  9. class Grade(BaseModel): # 继承这个基类
  10. name = models.CharField(verbose_name="班级", max_length=30, unique=True)
  11. desc = models.CharField(verbose_name="班级描述", max_length=50, null=True, blank=True)
  12. def __str__(self):
  13. return self.name
  14. # 定义一个 学生表 模型类
  15. class Student(BaseModel): # 继承这个基类
  16. name = models.CharField(max_length=30, verbose_name="姓名")
  17. phone = models.CharField(max_length=11, verbose_name="手机号", unique=True)
  18. qq = models.CharField(max_length=11, verbose_name="qq", unique=True)
  19. grade = models.ForeignKey(Grade, on_delete=models.CASCADE)
  20. def __str__(self):
  21. return self.name

这个应用的forms.py

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

2.1、实现增加表记录-POST接口

  1. from django.core.paginator import Paginator
  2. from django.forms import model_to_dict
  3. from django.shortcuts import render
  4. from django.views import View
  5. from django.http.response import JsonResponse
  6. from django.db.models import Q
  7. from . import forms, models
  8. class GradeView(View):
  9. # 用于给班级表新增记录
  10. def post(self, request):
  11. form = forms.GradeForm(request.POST)#把请求参数传递给 表单验证
  12. if form.is_valid():
  13. obj = form.save() # 保存到数据库,并返回这个记录的对象
  14. return JsonResponse({"code": 0, "msg": "操作成功", "id": obj.id})
  15. return JsonResponse({"code": -1, "msg": form.errors.get_json_data()})
  16. # 如果没有校验通过,返回form的校验信息

注意:
别忘了把这个基于类的视图绑定好路由

接口工具调用一下接口,POST请求,新增记录
image.png
数据库存储正常image.pngimage.png

2.2、实现修改表记录-PUT接口

Django暂不支持PUT请求,获取不到PUT请求传递过来的参数

先定义一个中间件

用来解决PUT请求参数接收不到的问题
image.png

  1. from django.http import QueryDict
  2. from django.middleware.common import MiddlewareMixin
  3. class PutMiddleware(MiddlewareMixin):
  4. """
  5. 给 Django 的request对象 增加 一个 PUT 对象
  6. """
  7. def process_request(self, request):
  8. if request.method.upper() == "PUT":
  9. if "multipart" in request.content_type: # form-data
  10. # 上面这种是能传文件的那种form
  11. data, files = request.parse_file_upload(request.META, request)
  12. request.PUT = data
  13. request._files = files
  14. else:
  15. data = QueryDict(request.body) # 这种是把普通k-v传参的转成字典
  16. request.PUT = data

编写视图函数

  1. 先确定修改哪条记录
  2. 然后再修改 ```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):

  1. def put(self, request):
  2. id = request.PUT.get("id", "")
  3. if not id:
  4. return JsonResponse({"code": -1, "msg": "请传入要修改的id"})
  5. if not id.isdigit():
  6. return JsonResponse({"code": -1, "msg": "id是数字"})
  7. query_set = models.Grade.objects.filter(id=id)
  8. if not query_set.exists():
  9. return JsonResponse({"code": -1, "msg": "要修改的id不存在"})
  10. grade = query_set.first() # 定义的Grade 模型类的一个实例对象(就是表中的一条记录)
  11. form = forms.GradeForm(request.PUT, instance=grade) # 加入instance=模型类实例对象, 表明本次是修改记录,不是新增记录
  12. if form.is_valid():
  13. obj = form.save() # 保存到数据库
  14. return JsonResponse({"code": 0, "msg": "操作成功", "id": obj.id})
  15. return JsonResponse({"code": -1, "msg": form.errors.get_json_data()})
  1. **接口工具调用一下接口,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)
  2. <a name="szXN3"></a>
  3. ## 2.3、实现删除表记录-DELETE接口
  4. 因为DELETE请求不带参数,只能在url中通过 查询字符串来传参,确定删除哪条记录
  5. ```python
  6. from django.core.paginator import Paginator
  7. from django.forms import model_to_dict
  8. from django.shortcuts import render
  9. from django.views import View
  10. from django.http.response import JsonResponse
  11. from django.db.models import Q
  12. from . import forms, models
  13. class GradeVies(View):
  14. def delete(self, request):
  15. id = request.GET.get("id")
  16. # 因为DELETE请求不带参数,只能在url中通过 查询字符串来传参,确定删除哪条记录
  17. if not id:
  18. return JsonResponse({"code": -1, "msg": "请传入要修改的id"})
  19. if not id.isdigit():
  20. return JsonResponse({"code": -1, "msg": "id是数字"})
  21. query_set = models.Grade.objects.filter(id=id)
  22. if not query_set.exists():
  23. return JsonResponse({"code": -1, "msg": "要修改的id不存在"})
  24. query_set.delete()
  25. return JsonResponse({"code": 0, "msg": "删除成功!"})

1647408854(1).pngimage.png1647408902(1).png

2.5、实现查询表记录-GET接口请求

  1. 查询所有的数据 -> 分页
  2. 查询单条数据
  3. 模糊查询 -> 分页
  4. 筛选查询

用来实现灵活配置的模糊查询,支持分页

  1. from django.core.paginator import Paginator
  2. from django.forms import model_to_dict
  3. from django.shortcuts import render
  4. from django.views import View
  5. from django.http.response import JsonResponse
  6. from django.db.models import Q
  7. from . import forms, models
  8. class GradeView(View):
  9. #用于实现模糊查询 方式1 新增需要模糊匹配的字段时 需要改代码
  10. # def get(self, request):
  11. # """
  12. # 1、查询所有的数据 -》 分页
  13. # 2、查询单条数据
  14. # 3、模糊查询 -》分页
  15. # 4、筛选
  16. # """
  17. # limit = request.GET.get("limit", 10)
  18. # page = request.GET.get("page", 1)
  19. # search = request.GET.get("search", )
  20. # if search:
  21. # all_data = models.Grade.objects.filter(Q(name__contains=search) | Q(desc__contains=search))
  22. # else:
  23. # all_data = models.Grade.objects.all()
  24. #
  25. #
  26. # # all_data = models.Grade.objects.all()
  27. # paginator = Paginator(all_data, limit)
  28. # page_data = paginator.get_page(page) # [<grade<1>,<garde2>]
  29. # data_list = [model_to_dict(data) for data in page_data]
  30. # data = {"code": 0, "msg": "查询成功", "data": data_list, "count": paginator.count}
  31. # return JsonResponse(data)
  32. # 方式2 模糊查询,灵活配置的,不需要改代码,
  33. search_fields = ["name", "desc"] # 指定哪些字段支持模糊查询
  34. def get(self, request):
  35. limit = request.GET.get("limit", 10)
  36. page = request.GET.get("page", 1)
  37. search = request.GET.get("search", )
  38. if search:
  39. q = Q() # None
  40. for field in self.search_fields:
  41. d = {"%s__contains" % field: search}
  42. q = q | Q(**d)
  43. # all_data = models.Grade.objects.filter( Q(name__contains=search) | Q(desc__contains=search) )
  44. all_data = models.Grade.objects.filter(q)
  45. else:
  46. all_data = models.Grade.objects.all()
  47. paginator = Paginator(all_data, limit)
  48. page_data = paginator.get_page(page) # [<grade<1>,<garde2>]
  49. data_list = [model_to_dict(data) for data in page_data]
  50. data = {"code": 0, "msg": "查询成功", "data": data_list, "count": paginator.count}
  51. return JsonResponse(data)

用来实现先分类查询,再模糊查询

  1. # 先分类查询 再模糊匹配
  2. class GradeView(View):
  3. search_fields = ["name", "desc"] # 指定哪些字段支持模糊查询
  4. filter_fields = ["id", "name"]
  5. # model Grade
  6. def get(self, request):
  7. limit = request.GET.get("limit", 10)
  8. page = request.GET.get("page", 1)
  9. search = request.GET.get("search")
  10. query_dict = {} #{id:1,name:xxx} 用来存放筛选条件的字典
  11. q = Q() # None
  12. for field in self.filter_fields:
  13. value = request.GET.get(field)
  14. if value != None:
  15. query_dict[field] = value
  16. if search:
  17. for field in self.search_fields:
  18. d = {"%s__contains" % field: search}
  19. q = q | Q(**d)
  20. # all_data = models.Grade.objects.filter(q).filter(**query_dict)
  21. # 先模糊查询后,再分类 # 先模糊,后精确
  22. all_data = models.Grade.objects.filter(**query_dict).filter(q)
  23. # 先分类筛选后,再模糊查询 # 先精确,后模糊
  24. paginator = Paginator(all_data, limit)
  25. page_data = paginator.get_page(page) # [<grade<1>,<garde2>]
  26. data_list = [model_to_dict(data) for data in page_data]
  27. data = {"code": 0, "msg": "查询成功", "data": data_list, "count": paginator.count}
  28. 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