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的参数,查 ...
随机推荐
- 学习 | jQuery移动端页面组件化开发(一)
最近在学习移动端组件化开发web页面,其中有好多小细节,值的去思考. 主要介绍JS的思路,具体的代码就不贴了,主要是想表达出一种思路 总体来说 1.入口文件,在入口文件中导入插件,插件样式,jquer ...
- JVM垃圾回收行为的并行与并发
程序的并行和并发 程序的并发(Concurrent) 在操作系统中,是指一个时间段中有几个程序都处于己启动运行到运行完毕之间,且这几个程序都是在同一个处理器_上运行. 并发不是真正意义上的“同时进行” ...
- 2020年的100天——FLAGS
2020年的100天--FLAGS Reading <爱的博弈>-- 作者: 约翰·戈特曼 (John Gottman) / 娜恩·西尔弗 (Nan Silver) <人间失格> ...
- xshell评估过期(已解决)
登录英文版官网 https://www.netsarang.com/ 点击download 选择xshell 5 . 直接在页面中有红色*号的地方输入个人信息,licensetype 必须选 Hom ...
- 普转提Day1
T1 给定一个长度为N的序列,去掉其中连续的一部分使得剩下的部分没有重复元素. 很显然可以发现去掉的一部分只有三种情况:开头.中间.最后. 那么我们只需要枚举Hash就可以了.复杂度O(N^2). 不 ...
- 时间轮算法在Netty和Kafka中的应用,为什么不用Timer、延时线程池?
大家好,我是yes. 最近看 Kafka 看到了时间轮算法,记得以前看 Netty 也看到过这玩意,没太过关注.今天就来看看时间轮到底是什么东西. 为什么要用时间轮算法来实现延迟操作? 延时操作 Ja ...
- spring cloud consul 服务治理
对照系统安装响应consul文件(以window为例) 解压文件之后配置环境,进入Path添加文件所在目录, 测试:在文件所在目录下进入指令操作 输入 consul agent -dev 启动成功,在 ...
- Java基础——消息队列
1.消息队列的适用场景:商品秒杀.系统解耦.日志记录等 2.使用Queue实现消息对列 双端队列(Deque)是 Queue 的子类也是 Queue 的补充类,头部和尾部都支持元素插入和获取阻塞队列指 ...
- 【Linux】一些文件限制配置
linux资源限制配置文件是/etc/security/limits.conf:限制用户进程的数量对于linux系统的稳定性非常重要. limits.conf文件限制着用户可以使用的最大文件数,最大线 ...
- HTML中css水平居中的几种方式
1. 子元素为行内元素时,父元素使用 text-align: center; 实现子元素的水平居中: 2. 子元素为块级元素时, 2.1. 将子元素设置 margin: 0 auto; 实现居中: 2 ...