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的参数,查 ...
随机推荐
- C语言汇总3
16-18 1.常量 整型常量:1: 2: 3: 实型常量(小数):单精度常量[3.14],双精度常量(默认情况下)[10.1f] 字符型常量 ' 5 ',只要在双引号的任意的唯一一个字符就为字符型常 ...
- day54:django:锁和事务&Ajax&中间件Middleware
目录 1.ORM中的锁和事务 2.Ajax 3.中间件:Middleware 3.1 什么是中间件? 3.2 django请求的生命周期 3.3 中间件可以定义的5个方法 3.4 自定义中间件的流程 ...
- 【原创】一层Nginx反向代理K8S化部署实践
目录: 1)背景介绍 2)方案分析 3)实现细节 4)监控告警 5)日志收集 6)测试 一.背景介绍 如下图所示,传统方式部署一层Nginx,随着业务扩大,维护管理变得复杂,繁琐,耗时耗力和易 ...
- docker zookeeper 集群搭建
#创建集群目录 mkdir /opt/cluster/zk cd /opt/cluster/zk #清理脏数据[可跳过] docker stop zk-2181 docker stop zk-2182 ...
- Flutter中如何方便的获取音视频的长度
此次主要是flutter集成im,在发送视频时需要加上时长,但是用视频controller只能在初始化时具备路径才可以可以使用:just_audio插件中的方法进行获取 详情看官方文档:https:/ ...
- java安全编码指南之:异常处理
目录 简介 异常简介 不要忽略checked exceptions 不要在异常中暴露敏感信息 在处理捕获的异常时,需要恢复对象的初始状态 不要手动完成finally block 不要捕获NullPoi ...
- Spring学习(二)--Spring的IOC
1.依赖反转模式 依赖反转:高层次的模块不应该依赖于低层次的模块,两者都应该依赖于抽象接口.抽象接口不应该依赖于具体实现.而具体实现则应该依赖于抽象接口. 在面向对象编程领域中,依赖反转原则(Depe ...
- Python-组织结构-目录结构、包导入、__init__文件、模块内置变量、* 导入限制
__pycache__ .pyc文件,中间代码,提升python运行效率 目录 分档和归类 Python项目组织结构 包 模块 类 函数.变量 # 层级依次往下都是一对多关系 Python项目目录结构 ...
- RTThread DFS文件系统使用: 基于使用SFUD驱动的SPI FLASH之上的ELM FATFS文件系统
参考博文: 博文很长,但是实际要操作的步骤没几下. http://m.elecfans.com/article/730878.html 为了防止几年后文章链接找不到,我把文章复制过来了 /***** ...
- C# Redis分布式锁 - 单节点
为什么要用分布式锁? 先上一张截图,这是在浏览别人的博客时看到的. 在了解为什么要用分布式锁之前,我们应该知道到底什么是分布式锁. 锁按照不同的维度,有多种分类.比如 1.悲观锁,乐观锁; 2.公平锁 ...