day73:drf:drf视图相关类&路由Routers&创建虚拟环境
目录
3.5个视图扩展类:ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
4.GenericAPIView的视图子类:ListAPIView,CreateAPIView,RetrieveAPIView,UpdateAPIView,DestroyAPIView
5.视图集基类:ViewSet,GenericViewSet,ModelViewSet,ReadOnlyViewSet
3.DefaultRouter和SimpleRouter的区别(了解)
APIView
APIView总结
1.APIView中封装了自己的request和response
2.django:request.GET对应drf中的request.query_params
3.django:request.POST对应drf中的request.data
4.APIView中的response不需要写参数safe=False,ensure_ascii这些东西了,因为这些功能已经封装在response里面了
5.当我们在浏览器上访问一个url,给你回复的是一个界面。如果我们用postman访问url,给你返回的就是json数据。这是因为response中有相关配置导致的。
APIView实现代码
- class Students1View(APIView):
- # 获取所有数据接口
- def get(self,request):
- all_data = models.Student.objects.all() # 获取数据库中Student表中所有数据
- serializer = StudentSerializer(instance=all_data,many=True) # 将后端数据序列化
- return Response(serializer.data) # 将序列化之后的数据传递给前端
- # 添加一条记录的接口
- def post(self,request):
- data = request.data # 获取用户在前端输入的数据
- serializer = StudentSerializer(data=data) # 将数据反序列化
- if serializer.is_valid(): # 校验
- instance = serializer.save() # instance为添加的新纪录对象
- serializer = StudentSerializer(instance=instance) # 根据API规范,数据保存之后应该显示到前端上,所以需要将新添加的数据序列化
- return Response(serializer.data,status=status.HTTP_201_CREATED)
- else:
- print(serializer.errors)
- class Student1View(APIView):
- # 获取单条记录
- def get(self,request,pk):
- stu_obj = models.Student.objects.get(pk=pk)
- serializer = StudentSerializer(instance=stu_obj)
- return Response(serializer.data)
- # 更新单条记录
- def put(self,request,pk):
- stu_obj = models.Student.objects.get(pk=pk)
- data = request.data
- serializer = StudentSerializer(instance=stu_obj, data=data, partial=True)
- if serializer.is_valid():
- instance = serializer.save() # instance为添加的新纪录对象
- serializer = StudentSerializer(instance=instance)
- return Response(serializer.data)
- else:
- print(serializer.errors)
- # 删除单条记录
- def delete(self,request,pk):
- models.Student.objects.get(pk=pk).delete()
- return Response(None,status=status.HTTP_204_NO_CONTENT)
GenericAPIView:通用视图类
GenerivAPIView继承自APIView方法,主要增加了操作序列化器和数据库查询的方法。
- from rest_framework.generics import GenericAPIView
- class Students2View(GenericAPIView,):
- queryset = models.Student.objects.all() # 指明要使用的数据查询集[必须指定]
- serializer_class = StudentSerializer # 指明视图要使用的序列化器[可写可不写]
- # 通过get_serializer_class来控制不同条件下,使用不同的序列化器类
- def get_serializer_class(self):
- if self.request.method == 'GET':
- return Student2Serializer
- else:
- return StudentSerializer
- # 获取所有数据接口
- def get(self, request):
- # all_data = models.Student.objects.all()
- # serializer = StudentSerializer(instance=all_data, many=True)
- serializer = self.get_serializer(instance=self.get_queryset(), many=True)
- return Response(serializer.data)
- # 添加一条记录的接口
- def post(self, request):
- data = request.data
- serializer = self.get_serializer(data=data)
- if serializer.is_valid():
- instance = serializer.save() # instance为添加的新纪录对象
- serializer = self.get_serializer(instance=instance)
- return Response(serializer.data, status=status.HTTP_201_CREATED)
- else:
- print(serializer.errors)
- return Response({'error':'字段错误'})
- class Student2View(GenericAPIView):
- queryset = models.Student.objects.all()
- serializer_class = StudentSerializer
- # 获取单条记录
- def get(self, request, pk):
- # stu_obj = models.Student.objects.get(pk=pk)
- serializer = self.get_serializer(instance=self.get_object())
- return Response(serializer.data)
- # 更新单条记录
- def put(self, request, pk):
- # stu_obj = models.Student.objects.get(pk=pk)
- data = request.data
- serializer = self.get_serializer(instance=self.get_object(), data=data, partial=True)
- if serializer.is_valid():
- # print('>>>',serializer.data) #在save方法之前,不能调用data属性,serializer.data
- instance = serializer.save() # instance为添加的新纪录对象
- print(serializer.data) #之后可以看
- serializer = self.get_serializer(instance=instance)
- return Response(serializer.data)
- else:
- print(serializer.errors)
- # 删除单条记录
- def delete(self, request, pk):
- models.Student.objects.get(pk=pk).delete()
- return Response(None, status=status.HTTP_204_NO_CONTENT)
GenericAPIView中的属性和方法
serializer_class 指明视图使用的序列化器
get_serializer(self, *args, **kwargs) 返回序列化器对象,主要用来提供给Mixin扩展类使用,如果我们在视图中想要获取序列化器对象,也可以直接调用此方法
queryset 指明使用的数据查询集
get_queryset(self) 返回视图使用的查询集,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回queryset
属性,可以重写
get_object(self) 返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用。在视图中可以调用该方法获取详情信息的模型类对象。
get_serializer_class(self) 当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中通过返回不同的序列化器类名就可以让视图方法执行不同的序列化器对象了。
返回序列化器类,默认返回serializer_class
5个视图扩展类:ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
提供了几种后端视图(对数据资源进行增删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。
这五个扩展类需要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。
换句话说。就是你在视图中的get post put等这些方法中不用写里面的代码了,里面的代码相关的操作已经被封装到对应的Mixin中了。
- class Students3View(GenericAPIView,ListModelMixin,CreateModelMixin):
- queryset = models.Student.objects.all()
- serializer_class = StudentSerializer
- # 获取所有数据接口
- def get(self, request):
- return self.list(request)
- # 添加一条记录的接口
- def post(self, request):
- return self.create(request)
- class Student3View(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
- queryset = models.Student.objects.all()
- serializer_class = StudentSerializer
- # 获取单条记录
- def get(self, request, pk):
- return self.retrieve(request, pk)
- # 更新单条记录
- def put(self, request, pk):
- return self.update(request, pk)
- # 删除单条记录
- def delete(self, request, pk):
- return self.destroy(request, pk)
GenericAPIView的视图子类:ListAPIView,CreateAPIView,RetrieveAPIView,UpdateAPIView,DestroyAPIView
上面的代码还是过于麻烦,因为既要继承GenericAPIView又要继承Mixin系列的类。
所以将各自的操作封装成自己的APIView类。用哪个继承哪个。
而且连函数都不用写了,在???APIView类中已经有了,所以不用再写了,继承自己的APIView类即可。
- from rest_framework.generics import ListAPIView,CreateAPIView,RetrieveAPIView,UpdateAPIView,DestroyAPIView
- class Students4View(ListAPIView,CreateAPIView):
- queryset = models.Student.objects.all()
- serializer_class = StudentSerializer
- class Student4View(RetrieveAPIView,UpdateAPIView,DestroyAPIView):
- queryset = models.Student.objects.all()
- serializer_class = StudentSerializer
视图集基类:ViewSet,GenericViewSet,ModelViewSet,ReadOnlyViewSet
ViewSet
主要解决问题:之前我们在写视图类的时候,获取多条数据和提交数据放在了一个类中。获取单条数据,更新单条数据,删除多条数据放到了一个类中
这是因为多条数据操作时不需要指定pk值,而针对单条数据时,需要指定pk值。也就是说需要知道你要操作哪一条数据
这样我们就很矛盾。我们没法将5个方法放到同一个类中。
而下面的ViewSet就可以解决这个问题,将5个方法放到同一个类中
- from rest_framework.viewsets import ViewSet
- class Students5View(ViewSet):
- # 获取所有数据接口
- def get_all_student(self,request): # action
- all_data = models.Student.objects.all()
- serializer = StudentSerializer(instance=all_data,many=True)
- return Response(serializer.data)
- # 添加一条记录的接口
- def add_student(self,request):
- data = request.data
- serializer = StudentSerializer(data=data)
- if serializer.is_valid():
- instance = serializer.save() #instance为添加的新纪录对象
- serializer = StudentSerializer(instance=instance)
- return Response(serializer.data,status=status.HTTP_201_CREATED)
- else:
- print(serializer.errors)
- def get_one(self,request,pk):
- stu_obj = models.Student.objects.get(pk=pk)
- serializer = StudentSerializer(instance=stu_obj)
- return Response(serializer.data)
通过上面代码我们可以看出。单条数据操作和多条数据被放到了一个类中。并且方法名也不再局限于必须要使用get post put...这些方法名了。
这是因为在urls.py中的as_view方法做了一个请求方法和对应函数名的指定。
而获取单条数据和获取多条数据能够共存在一个类中,是因为他们处于两个url中。虽然都是get请求过去的,但是他们在不同的url中,会执行各自的视图方法
通过下面url,我们就可以发挥出ViewSet的用处了:
- path('students5/', views.Students5View.as_view({'get':'get_all_student','post':'add_student'})),
- re_path('students5/(?P<pk>\d+)/', views.Students5View.as_view({'get':'get_one'})),
ViewSet+????APIView
用我们刚才学的ViewSet和之前的???APIView做一个结合~
效果:即放到了一个类中,而且各个方法里不用写详细代码(????APIView的作用)
- """发挥下ViewSet的作用"""
- from rest_framework.viewsets import ViewSet
- from rest_framework.generics import ListAPIView,CreateAPIView,RetrieveAPIView
- class Student2ViewSet(ViewSet,ListAPIView,CreateAPIView,RetrieveAPIView):
- queryset = Student.objects.all()
- serializer_class = StudentModelSerializer
- def get_all(self,request):
- return self.list(request)
- def add_student(self,request):
- return self.create(request)
- def get_one(self,request,pk):
- return self.retrieve(request)
GenericViewSet+???Mixin
效果和Viewset+???APIView是相同的
- from rest_framework.viewsets import GenericViewSet
- from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin
- class Student3ViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin):
- queryset = Student.objects.all()
- serializer_class = StudentModelSerializer
- def get_all(self,request):
- return self.list(request)
- def add_student(self,request):
- return self.create(request)
- def get_one(self,request,pk):
- return self.retrieve(request)
现在我们的代码是这个样子的。美中不足是我们还需要自己写def方法,其实我们希望的是类里面没有def方法的
其实。这个需求刚才在前面已经提到了。
只需要在urls.py中将get post put这类请求类型直接与Mixin中内置的list,create,update等动作方法关联起来。
这样它就会自动去执行里面的list,create,update方法。不需要你在视图里定义一个函数名称然后再return self.create()了。
urls.py如下所示:
- urlpatterns = [
- path("students7/", views.Student4ViewSet.as_view({"get": "list", "post": "create"})),
- re_path("students7/(?P<pk>\d+)/", views.Student4ViewSet.as_view({"get": "retrieve","put":"update","delete":"destroy"})),
- ]
url直接就是{请求类型:action动作名},这样我们在视图那一块的代码又可以缩减了。函数全部无需定义了。
经过改良后,视图代码如下所示:
- from rest_framework.viewsets import GenericViewSet
- from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
- class Student4ViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
- queryset = Student.objects.all()
- serializer_class = StudentModelSerializer
ModelViewSet
上面的代码,在导入和继承的时候太麻烦了,需要写5个Mixin类
这时出现了ModelViewSet,ModelViewSet同时继承ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin这五个类。
这样写起来就更加简单了。
终极版如下所示:
- from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
- from rest_framework.decorators import action
- class StudentModelViewSet(ModelViewSet):
- queryset = Student.objects.all()
- serializer_class = StudentModelSerializer
ReadOnlyViewset
继承自GenericViewSet
,同时包括了ListModelMixin、RetrieveModelMixin。
视图集中定义附加action动作
在视图集中,除了上述默认的方法动作外,还可以添加自定义动作,进行扩展。
举例,比如做一个登录方法login:
- from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
- class StudentModelViewSet(ModelViewSet):
- queryset = Student.objects.all()
- serializer_class = StudentModelSerializer
- def login(self,request): # 这个就可以称为自定义的action动作
- """学生登录功能"""
- return Response({"message":"登录成功"})
urls.py这样写
- urlpatterns = [
- path("students8/", views.StudentModelViewSet.as_view({"get": "list", "post": "create"})),
- re_path("students8/(?P<pk>\d+)/",
- views.StudentModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
- path("stu/login/",views.StudentModelViewSet.as_view({"get":"login"}))
- ]
在视图集中,我们可以通过action对象属性来获取当前请求视图集时的action动作是哪个。
- from rest_framework.viewsets import ModelViewSet
- from students.models import Student
- from .serializers import StudentModelSerializer
- from rest_framework.response import Response
- class StudentModelViewSet(ModelViewSet):
- queryset = Student.objects.all()
- serializer_class = StudentModelSerializer
- def get_new_5(self,request):
- """获取最近添加的5个学生信息"""
- # 操作数据库
- print(self.action) # 获取本次请求的视图方法名
- '''通过路由访问到当前方法中.可以看到本次的action就是请求的方法名'''
路由:Routers
如何添加路由数据
如何添加路由数据,并且和视图函数做关联:
- from django.urls import path, re_path
- from . import views
- urlpatterns = [
- ...
- ]
- """使用drf提供路由类router给视图集生成路由列表"""
- # 实例化路由类
- # drf提供一共提供了两个路由类给我们使用,他们用法一致,功能几乎一样
- from rest_framework.routers import DefaultRouter
- router = DefaultRouter()
- # 注册视图集
- # router.register("路由前缀",视图集类)
- router.register("router_stu",views.StudentModelViewSet)
- # 把生成的路由列表追加到urlpatterns
- urlpatterns += router.urls
上面的代码就成功生成了路由地址[增/删/改/查一条/查多条的功能],但是不会自动帮我们在视图集自定义方法的路由。
所以我们如果也要给自定义方法生成路由,则需要进行action动作的声明。
在视图集中附加action声明
在视图集中,如果想要让Router自动帮助我们为自定义的动作生成路由信息,需要使用rest_framework.decorators.action
装饰器。
以action装饰器装饰的方法名会作为action动作名,与list、retrieve等同。
action装饰器可以接收两个参数:
methods: 声明该action对应的请求方式,列表传递
detail:
声明该action的路径是否与单一资源对应,及是否是
- xxx/<pk>/action方法名/
True 表示路径格式是
xxx/<pk>/action方法名/
False 表示路径格式是
xxx/action方法名/
- from rest_framework.viewsets import ModelViewSet
- from rest_framework.decorators import action
- class StudentModelViewSet(ModelViewSet):
- queryset = Student.objects.all()
- serializer_class = StudentModelSerializer
- # methods 设置当前方法允许哪些http请求访问当前视图方法
- '''detail 设置当前视图方法是否是操作一个数据'''
- # detail为True,表示路径名格式应该为 router_stu/{pk}/login/
- @action(methods=['get'], detail=True)
- def login(self, request,pk):
- """登录"""
- ...
- # detail为False 表示路径名格式应该为 router_stu/get_new_5/
- @action(methods=['put'], detail=False)
- def get_new_5(self, request):
- """获取最新添加的5个学生信息"""
- ...
DefaultRouter和SimpleRouter的区别(了解)
DefaultRouter与SimpleRouter的区别是,DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据。
比如使用DefaultRouter时你访问一下http://127.0.0.1:8001/router_stu/
会看到一个页面。
而SimpleRouter会报错,一般都需要有个查看所有接口的页面,所以我们基本都是用的是DefaultRouter
创建虚拟环境
1.安装虚拟环境
- # 1.管理员方式打开终端
- # 2.安装虚拟环境
- pip install virtualenv -i https://pypi.douban.com/simple
- # 3.终端关闭,再重新打开
- # 4.注意:创建[环境名称]文件夹,放置所有的环境,进入指定目录 D:/envs
- # 5.创建虚拟环境
- virtualenv 环境名称 'C:\python\python3.6.exe'
- '''这样写的前提是你的电脑已经将python加入到环境变量中'''
- virtualenv 环境名称 --python=python3.6
2.激活虚拟环境
- # 1.进入到虚拟环境文件夹下的Scripts目录
- activate '''激活虚拟环境'''
- # 2.退出虚拟环境
- deactivate '''退出虚拟环境'''
3.在虚拟环境中安装模块
- # 1.激活虚拟环境
- # 2.在激活的虚拟环境中安装模块
- pip3 install django==2.2 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
- # 3.搭建项目环境,在pycharm选择解释器时,选择你之前已经创建好的虚拟环境
4.在pycharm上使用虚拟环境
附:APIView思维导图
附:drf的执行流程图
day73:drf:drf视图相关类&路由Routers&创建虚拟环境的更多相关文章
- drf之视图类与路由
视图 Django REST framwork 提供的视图的主要作用: 控制序列化器的执行(检验.保存.转换数据) 控制数据库查询的执行 2个视图基类 APIView rest_framework.v ...
- DRF的视图和路由
DRF的视图 APIView Django中写CBV的时候继承的是View,rest_framework继承的是APIView, urlpatterns = [ url(r'^book$', Book ...
- DRF视图集的路由设置
在使用DRF视图集时,往往需要配一大堆路由,例如: # views.py class DepartmentViewSet(ListModelMixin,CreateModelMixin,Retriev ...
- DRF 的视图,路由和渲染器
DRF 的视图,路由和渲染器 1 视图 简单的增删改查 : ModelViewSet; 复杂的操作使用APIView 和 GenericViewSet APIView(View) class Home ...
- DRF教程4-视图集和路由类
rest框架包括一个处理viewset的抽象,允许开发人员集中精力处理api交互和建模,url构造都根据常见方式自动处理. ViewSet类 几乎和VIew类一样,不过它提供read,update这样 ...
- DRF 视图家族及路由层补充
目录 视图家族 一.views视图类 1.APIView类 2.GenericAPIView类(generics中) 二.mixins类:视图辅助工具 1.RetrieveModelMixin 2.L ...
- DRF中五大扩展类及视图集的介绍
五个扩展类 (1)ListModelMixin 列表视图扩展类,提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码. 该Mixin的list方法会对 ...
- DRF (Django REST framework) 中的视图扩展类
2. 五个扩展类 1)ListModelMixin 列表视图扩展类,提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码. 该Mixin的list方法 ...
- DRF框架(五)——context传参,二次封装Response类,两个视图基类(APIView/GenericAPIView),视图扩展类(mixins),子类视图(工具视图),视图集(viewsets),工具视图集
复习 1.整体修改与局部修改 # 序列化get (给前端传递参数) #查询 ser_obj = ModelSerializer(model_obj) #只传递一个参数,默认是instance的参数,查 ...
随机推荐
- 预科班D9
2020.09.17星期四 预科班D9 学习内容: 一.列表与字典的嵌套 大前提:将所有同学的信息存起来,取值需求 1.取第二个学生的性别 stus_info = [ {"name" ...
- python蟒蛇绘制
使用IDLE的文件方式编写代码并保存为PythonDraw.py文件 python蟒蛇绘制 import turtle引入了海龟绘图体系 使用setup函数,设定了一个宽650像素和高350像素的窗体 ...
- ubuntu 开启samba
sudo apt-get update sudo apt-get install samba samba-common sudo mkdir /home/vagrant/share sudo chmo ...
- 新手C++ 练习项目--计算器
本篇博客用于记录我自己用C++实现的一个计算器,目标是完成加减乘除带括号的四则运算,并在后期用工厂设计模式加以优化. Part 1:calculate 1+1=2 实现这样的一个式子的计算,只需要用到 ...
- 内存操作【memset】【memcpy】
void *memset(void *s, int c, unsigned long n); 将指针变量 s 所指向的前 n 字节的内存单元用一个"整数" c 替换,注意 c 是 ...
- Python练习题 035:Project Euler 007:第10001个素数
本题来自 Project Euler 第7题:https://projecteuler.net/problem=7 # Project Euler: Problem 7: 10001st prime ...
- 2.1 java语言概述
链接:https://pan.baidu.com/s/1ab2_KapIW-ZaT8kedNODug 提取码:miao
- SPI应用 用SPI控制一个数字电位器
Controlling a Digital Potentiometer Using SPI In this tutorial you will learn how to control the AD5 ...
- .NET Standard 系列
.NET Standard 是一套正式的 .NET API 规范,有望在所有 .NET 实现中推出. 推出 .NET Standard 的背后动机是要提高 .NET 生态系统中的一致性. ECMA 3 ...
- linux网络收包过程
记录一下linux数据包从网卡进入协议栈的过程,不涉及驱动,不涉及其他层的协议处理. 内核是如何知道网卡收到数据的,这就涉及到网卡和内核的交互方式: 轮询(poll):内核周期性的检查网卡,查看是否收 ...