drf之视图基类与扩展类

drf之视图基类与扩展类

Django REST framwork 提供的视图的主要作用:

  • 控制序列化器的执行(检验、保存、转换数据)
  • 控制数据库查询的执行

我们可以使用View来编写CBV格式的视图,APIView继承了view,封装了request,提供了更多的功能

drf中实际上还有很多别的视图类,增加了操作序列化器和数据库查询的方法,并且进一步精简代码,十分方便

两个视图基类

APIView

rest_framework.views.APIView

APIView是REST framework提供的所有视图的基类,继承自Django的View父类。

APIViewView的不同之处在于:

  • 传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
  • 视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;
  • 任何APIException异常都会被捕获到,并且处理成合适的响应信息;
  • 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。

APIView中仍以常规的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。在上一篇博客中已经包含了使用序列器和APIView

下面是对图书表操作的例子

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.models import Book
from app01.ser import BookSerializer
# 基于APIView写的
class BookView(APIView):
    def get(self,request):
    # 获取所有书籍
        book_list=Book.objects.all()
        book_ser=BookSerializer(book_list,many=True)
        return Response(book_ser.data)
    def post(self,request):
    # 添加书籍
        book_ser = BookSerializer(data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.data)
        else:
            return Response({'status':101,'msg':'校验失败'})

class BookDetailView(APIView):
    def get(self, request,pk):
    # 路由中有名分组,获取pk值
        book = Book.objects.all().filter(pk=pk).first()
        book_ser = BookSerializer(book)
        return Response(book_ser.data)

    def put(self, request,pk):
        book = Book.objects.all().filter(pk=pk).first()
        book_ser = BookSerializer(instance=book,data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.data)
        else:
            return Response({'status': 101, 'msg': '校验失败'})

    def delete(self,request,pk):
        ret=Book.objects.filter(pk=pk).delete()
        return Response({'status': 100, 'msg': '删除成功'})
# models.py
class Book(models.Model):
    name=models.CharField(max_length=32)
    price=models.DecimalField(max_digits=5,decimal_places=2)
    publish=models.CharField(max_length=32)
#ser.py
class BookSerializer(serializers.ModelSerializer):
    # 模型类序列化器
    class Meta:
        model=Book
        fields='__all__'
# urls.py
path('books/', views.BookView.as_view()),
re_path('books/(?P<pk>\d+)', views.BookDetailView.as_view()),

GenericAPIView

导入GenericAPIView,看一看源码

可以看到,继承了APIView,并且自带两个属性,querysetserializer_class,其中,queryset就是使用APIview时候,用数据库查询到的对象,serializer_class就是序列化器类,于是我们把这两个东西传进去

# urls.py
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^book/', views.Book1View.as_view()),
    url('books2/(?P<pk>\d+)/', views.Book1DetailView.as_view())
]
# views.py
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from hwk01.models import Book
from hwk01.ser import BookSerializer
# Create your views here.

class Book1View(GenericAPIView):
    # queryset要传queryset对象,查询了所有的图书
    queryset = Book.objects
    # 这里不传queryset对象也没关系,基类中会帮你.all()获取成queryset对象
    serializer_class = BookSerializer
    # 传入序列化器类

    def get(self, request):
        book_list = self.get_queryset()
        # 获得视图使用的查询集,就是Book.object.all()
        book_ser = self.get_serializer(book_list, many=True)
        # 就是BookSerializer(book_list,many=True)
        return Response(book_ser.data)

    def post(self, request):
        book_ser = self.get_serializer(data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.data)
        else:
            return Response({'status': 101, 'msg': '校验失败'})


class Book1DetailView(GenericAPIView):
    queryset = Book.objects
    serializer_class = BookSerializer

    def get(self, request, pk):
        book = self.get_object()
        # get_object和get_queryset的区别,一个获取一个,一个获取全部
        book_ser = self.get_serializer(book)
        return Response(book_ser.data)

    def put(self, request, pk):
        book = self.get_object()
        book_ser = self.get_serializer(instance=book, data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.data)
        else:
            return Response({'status': 101, 'msg': '校验失败'})

    def delete(self, request, pk):
        ret = self.get_object().delete()
        return Response({'status': 100, 'msg': '删除成功'})

如果只是使用GenericAPIView可以发现,跟使用APIView没有什么区别,只是把模型数据和序列化器在类里面传入了。因此,我们要对操作别的基类的时候,可以只是换掉视图的名字,模型类和序列化器,其他代码复制过去就可以直接用了。

当然这么多重复的代码,drf也提供了扩展类来进一步精简

5个视图扩展类写的接口

from rest_framework.mixins import  ListModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin
# 从这里导入

这些接口中自带了我们上面写的查询全部,新增,删除,更改等等操作,还自带了过滤器和分页器,下面直接上使用方法

# urls.py
url(r'^book2/', views.Book2View.as_view()),
url('books2/(?P<pk>\d+)/', views.Book2DetailView.as_view())
# views.py
class Book2View(GenericAPIView,ListModelMixin,CreateModelMixin):
    queryset=Book.objects
    serializer_class = BookSerializer
    def get(self,request):
        return self.list(request)
		# 获取全部数据,使用list
    def post(self,request):
        return self.create(request)
    	# 新增一个数据,用create

class Book2DetailView(GenericAPIView,RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin):
    queryset = Book.objects
    serializer_class = BookSerializer
    def get(self, request,pk):
        return self.retrieve(request,pk)
		# 查询单个数据:retrieve,获取id值,自动查询
    def put(self, request,pk):
        return self.update(request,pk)
		# 更新单个数据,update
    def delete(self,request,pk):
        return self.destroy(request,pk)
    	# 删除单个数据,destroy

相比起只使用GenericAPI,代码又精简了一些

GenericAPIView的视图子类

比起上面mixin类更加恐怖的精简,只要写几行代码导入模型和序列化器,url配置一下就能实现上面的操作了

from rest_framework.generics import GenericAPIView,CreateAPIView,RetrieveAPIView,DestroyAPIView,UpdateAPIView,ListAPIView
# 在导入GenericAPIView的地方导入
# urls.py
url(r'^book3/', views.Book3View.as_view()),
url('books3/(?P<pk>\d+)/', views.Book3DetailView.as_view())
# views.py
class Book3View(ListAPIView,CreateAPIView):
# 不需要pk值的视图,查询全部和新增:List,Create
    queryset = Book.objects
    serializer_class = BookSerializer

class Book3DetailView(RetrieveAPIView,DestroyAPIView,UpdateAPIView):
# 需要pk的视图,Retrieve,Destroy,Update
    queryset = Book.objects
    serializer_class = BookSerializer

复杂的接口仅需要几行就写完了,甚至还可以更加精简!

两两想通过类里面继承的类可以写在一起

... import ListCreateAPIView
class Book3View(ListCreateAPIView):
    queryset = Book.objects
    serializer_class = BookSerializer

ViewsetMixin

这个类重写了as_view方法

暂时只学到在路由中设置方法,支持根据请求触发指定的方法

# views.py
from rest_framework.viewsets import ViewSetMixin
class Book6View(ViewSetMixin,APIView): #一定要放在APIVIew前
    def get_all_book(self,request):
        print("xxxx")
        book_list = Book.objects.all()
        book_ser = BookSerializer(book_list, many=True)
        return Response(book_ser.data)
# urls.py
path('books6/', views.Book6View.as_view(actions={'get': 'get_all_book'})),
# 动作写在action中,接收get请求时,触发后面的方法名
posted @ 2020-07-08 19:48  黑猫警长紧张  阅读(181)  评论(0编辑  收藏  举报