Django REST framwork 提供视图的主要作用:
REST framework 提供了众多的通用视图基类与扩展类,以简化视图的编写。
from rest_framework.views import APIView
APIView
是REST framework 提供的所有视图的基类, 继承自Django的View
父类
APIView
相比较与 View
, 它对Django原生的 request
对象进行了处理转成了 DRF 的 request
对象
并重写了 dispatch
方法, 在路由分发之前会对请求进行身份认证, 权限检查, 频率控制
重写了View中通过本次请求的方式动态的反射到自定义继承APIView类实例化的对象中定义的请求方法
设置全局异常处理
处理完毕异常以后使用的是 drf 的 response 对象对请求响应
APIView
中仍以常规的类视图定义方法来实现get( ) 、post( ) 或者其他请求方式的方法from rest_framework.views import APIView
from django.db import models
class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
city = models.CharField(max_length=32, null=True)
email = models.EmailField()
def __str__(self):
return self.name
from mydrf import models # 项目名:mydrf
from rest_framework import serializers
class PublishSerializer(serializers.ModelSerializer):
class Meta:
model = models.Publish
fields = "__all__"
from mydrf import models
from rest_framework.views import APIView
from rest_framework.response import Response
from mydrf.serializers import PublishSerializer
class PublishView(APIView):
# 获取所有书
def get(self, request):
publish_qs = models.Publish.objects.all()
# 有多条数据的时候一定要添加many=True
publish_ser = PublishSerializer(instance=publish_qs, many=True)
return Response(publish_ser.data)
# 新增数据
def post(self, request):
publish_ser = PublishSerializer(data=request.data)
if publish_ser.is_valid():
publish_ser.save()
return Response(publish_ser.data)
else:
# publish_ser.errors
return Response("error")
class Publish2View(APIView):
# 获取一条
def get(self, request, id):
publish_obj = models.Publish.objects.filter(pk=id).first()
publish_ser = PublishSerializer(instance=publish_obj)
return Response(publish_ser.data)
# 修改数据
def put(self, request, id):
publish_obj = models.Publish.objects.filter(pk=id).first()
publish_ser = PublishSerializer(instance=publish_obj, data=request.data)
if publish_ser.is_valid():
publish_ser.save()
return Response(publish_ser.data)
else:
return Response(publish_ser.errors)
# 删除数据
def delete(self, request, id):
# 直接删除数据,拿到影响条数的一个列表
rows = models.Publish.objects.filter(pk=id).delete()
# 取出来判断一下
if rows[0] > 0:
return Response('数据删除成功!')
else:
return Response('数据不存在!')
path('publish/', views.PublishView.as_view()),
path('publish/' , views.Publish2View.as_view()),
继承关系:APIView继承View
APIView基于View的拓展:
APIView重写了View的dispatch方法,在该方法中实现了以下一些功能:
对来的原生请求对象request进行了封装.
提供了对包装过后的请求对象的三段认证:认证,权限控制、频率控制
重写了
View
中通过本次请求的方式动态的反射到自定义继承APIView类实例化的对象中定义的请求方法使用异常处理处理2,3步骤中的异常
处理完毕异常以后使用drf的Response对象响应请求
针对路由配置:
APIVIew
, 主要增加了操作序列化器和数据库查询的方法, 作用是为下面Mixin扩展类的执行提供方法支持; 通常在使用时, 可搭配一个或多个Mixin扩展类from rest_framework.generics import GenericAPIView
属性 | 作用 |
---|---|
queryset (常用) | 需要序列化的查询集 |
serializer_class (常用) | 指定使用的序列化器 |
pagination_class | 分页控制类 |
filter_backends | 过滤控制后端 |
lookup_field | 查询单一数据库对象时使用的条件字段,默认为**’pk’** |
方法 | 作用 |
---|---|
get_queryset( ) (常用) | 获取QuerySet查询集 |
get_object( ) (常用) | 获取一条数据对象 |
get_serializer( ) | 返回序列化器对象,可以其他视图或扩展类使用 |
get_serializer_class | 返回序列化器类,默认返回serializer_class,可以重写 |
from mydrf.serializers import PublishSerializer
from rest_framework.generics import GenericAPIView
# 查看所有, 新增一条
class PublishListCreateView(GenericAPIView):
queryset = models.Publish.objects.all() # 需要要序列化的数据
serializer_class = PublishSerializer # 指定序列化类
def get(self, request):
query_set = self.get_queryset() # 获取要序列化的数据
serializer = self.get_serializer(query_set, many=True) # 获取序列化之后得到的对象
return Response(serializer.data)
def post(self, request):
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.error)
# 查一条, 改, 删
class PublishUpdateDestroyRetrieveView(GenericAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
def get(self, request, *args, **kwargs):
publish_obj = self.get_object() # 获取要序列化的单条数据
serializer = self.get_serializer(publish_obj) # 获取序列化之后得到的对象
return Response(serializer.data)
def put(self, request, *args, **kwargs):
publish_obj = self.get_object()
serializer = self.get_serializer(instance=publish_obj, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.error)
def delete(self, request, *args, **kwargs):
rows = self.get_object().delete()
if rows[0] > 0:
return Response('')
else:
return Response('该数据不存在!')
path('publish1/', views.PublishListCreateView.as_view()),
path('publish1/' , views.PublishUpdateDestroyRetrieveView.as_view()),
查询条件使用的条件字段是有
lookup_field
属性来控制的, 默认是pk
, 可以修改
扩展类 | 提供方法 | 用途 |
---|---|---|
ListModelMixin | list() | 获得多条数据对象 |
CreateModelMixin | create() | 新建单一数据对象 |
RetrieveModelMixin | retrieve() | 获得单一数据对象 |
UpdateModelMixin | update() | 更新一条数据 |
DestroyModelMixin | destroy() | 删除单⼀一对象 |
GenericAPIView
父类,因为五个扩展类的实现需要调用GenericAPIView
提供的序列化器与数据库查询的方法from rest_framework.generics import GenericAPIView # 视图基类
from rest_framework.mixins import CreateModelMixin # 增
from rest_framework.mixins import DestroyModelMixin # 删
from rest_framework.mixins import UpdateModelMixin # 改
from rest_framework.mixins import RetrieveModelMixin # 查一条
from rest_framework.mixins import ListModelMixin # 查所有
# 获取所有, 新增一条
class PublishListCreateView2(GenericAPIView, CreateModelMixin, ListModelMixin):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request):
return self.create(request)
# 获取一条, 修改, 删除
class PublishDeUpReView2(GenericAPIView, DestroyModelMixin, UpdateModelMixin, RetrieveModelMixin):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
path('publish2/', views.PublishListCreateView2.as_view()),
path('publish2/' , views.PublishDeUpReView2.as_view()),
子类 | 提供方法 | 继承自 |
---|---|---|
CreateAPIView | 提供 post 方法 | GenericAPIView、CreateModelMixin |
ListAPIView | 提供 get 方法 | GenericAPIView、ListModelMixin |
RetireveAPIView | 提供 get 方法 | GenericAPIView、RetrieveModelMixin |
DestoryAPIView | 提供 delete 方法 | GenericAPIView、DestoryModelMixin |
UpdateAPIView | 提供 put 和 patch 方法 | GenericAPIView、UpdateModelMixin |
ListCreateAPIView | 提供 get、post方法 | GenericAPIView、ListModelMixin、CreateModelMixin |
RetrieveUpdateAPIView | 提供 get、put、patch方法 | GenericAPIView、RetrieveModelMixin、UpdateModelMixin |
RetrieveDestroyAPIView | 提供 get、put、patch方法 | GenericAPIView、RetrieveModelMixin、DestoryModelMixin |
RetrieveUpdateDestoryAPIView | 提供 get、put、patch、delete方法 | GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin |
from rest_framework.generics import CreateAPIView # 新增
from rest_framework.generics import ListAPIView # 查看所有
from rest_framework.generics import ListCreateAPIView # 查看所有新增一个
from rest_framework.generics import RetrieveAPIView # 查看一个
from rest_framework.generics import DestroyAPIView # 删除一个
from rest_framework.generics import UpdateAPIView # 修改一个
from rest_framework.generics import RetrieveUpdateAPIView # 查看一个,修改一个
from rest_framework.generics import RetrieveDestroyAPIView # 查看一个,删除一个
from rest_framework.generics import RetrieveUpdateDestroyAPIView # 查看一个,修改一个,删除一个
# class PublishView3(CreateAPIView,ListAPIView): # 或者下面写法,可以自行组合
class PublishView3(ListCreateAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
# class PublishReDeUpView3(RetrieveAPIView, DestroyAPIView, UpdateAPIView): # 或者下面写法
class PublishReDeUpView3(RetrieveUpdateDestroyAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
path('publish3/', views.PublishView3.as_view()),
path('publish3/' ,views.PublishDeUpReView2.as_view()),
不同的视图集继承了不同的视图基类、视图子类或者视图扩展类, 我们使用视图集可以更加方便的操作数据
在没有视图集之前, DRF五大接口帮我们实现数据操作 : get_one, get_list, post, put, delete
我们可以写一个类, 然后继承GenericAPIView的九个视图子类来实现五个接口
但是出现的问题是 : 查询所有使用 get 方法, 查询一条也是使用 get 方法, 但是在Python中, 同一个类中不能有相同的方法名
于是DRF的作者在这个类中不再实现get( )、post( )等方法, 而是将它们映射成对应的 action 行为
查询所有的 get( )
方法映射成 list( )
, 查询一条的 get( )
方法映射成 retrive( )
, 这就是视图集的由来
list() # 提供一组数据
retrieve() # 提供单个数据
create() # 创建数据
update() # 保存数据
destory() # 删除数据
as_view( )
方法的时候,才会将action动作与具体请求方式相互映射继承自:APIView
与 ViewSetMixin
作用 : 与APIView基本类似,提供了身份认证、权限校验、流量管理等
ViewSet主要通过继承ViewSetMixin来实现在调用as_view( )
时传入字典的映射处理工作
缺点 : 在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法
- 使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写
- 而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写
- 但是Mixin扩展类依赖与
GenericAPIView
,所以还需要继承GenericAPIView
- GenericViewSet就帮助我们完成了这样的继承工作
GenericAPIView
与ViewSetMixin
as_view()
时传入字典(如{'get':'list'}
)的映射处理工作的同时,还提供了GenericAPIView
提供的基础方法,可以直接搭配Mixin扩展类使用GenericViewSet
,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixinGenericViewSet
,同时包括了ListModelMixin、RetrieveModelMixinfrom rest_framework.viewsets import ModelViewSet # 继承GenericViewSet + 五个接口都有
from rest_framework.viewsets import ReadOnlyModelViewSet # 继承GenericViewSet + 只有读两个接口
from rest_framework.viewsets import GenericViewSet # 继承GenericAPIView与ViewSetMixin
from rest_framework.viewsets import ViewSet # 继承的APIView与ViewSetMixin
from rest_framework.viewsets import ViewSetMixin # 提供修改路由中ac_view()类方法的actions参数
class PublishView4(ModelViewSet):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
# 需要书写方法映射关系
path('publish4/', views.PublishView4.as_view(actions={
'get':'list','post':'create'})),
path('publish4/' , views.PublishView4.as_view(actions={
'get':'retrieve','put':'update','delete':'destroy'})),
as_view()
方法的时候需要书写方法与action
的映射关系, 因为ViewSetMixin
重写了父类的as_view()
方法, 在书写路由的时候就需要以上面的方式书写ViewSetMixin
的时候一定要将其放在最左边, 这样在调用as_view()
方法的时候才会先调用ViewSetMixin
中的as_view()
方法ViewSetMixin
在视图集中,除了上述默认的方法动作外,还可以添加自定义动作
class PublishView5(GenericViewSet):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
# 自定义的 action
def get_xxx(self,request):
query_set = self.get_queryset()
serializer = self.get_serializer(query_set,many=True)
return Response(serializer.data)
path('publish5/', views.PublishView5.as_view(actions={
'get': 'get_xxx'})),
在视图集中,我们可以通过action对象属性来获取当前请求视图集时的action动作是哪个
class PublishView5(GenericViewSet):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
# 自定义的 action
def get_xxx(self,request):
query_set = self.get_queryset()
serializer = self.get_serializer(query_set,many=True)
print(self.action) # get_xxx
return Response(serializer.data)
ps : 在 Pycharm 中可以鼠标右击一个视图类------>Diagrams------>Show Diagrams 来查看这个类的继承关系