码迷,mamicode.com
首页 > 其他好文 > 详细

rest_framework视图家族

时间:2020-07-19 23:27:00      阅读:62      评论:0      收藏:0      [点我收藏+]

标签:https   first   图片   管理   不能   containe   ror   写视图   前端   

表与序列化类准备

  • models.py
from django.db import models

# Create your models here.
class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    publish = models.CharField(max_length=32)

    def __str__(self):
        return self.name
  • ser.py(使用了ModelSerializer序列化组件)
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from app01 import models

class BookModelSerializer(serializers.ModelSerializer):
    class Meta():
        model = models.Book
        fields = ‘__all__‘
    def validate_name(self,name):
        if name == ‘x‘:
            raise ValidationError(‘名字不能是x‘)
        else:
            return name

基于APIView类的视图

  • 类中的方法名必须是get post put delete等
  • 在每个方法内部需要通过models获取需要处理的数据对象
  • 使用起来较为繁琐
# 基于APIView的视图
from rest_framework.views import APIView
class BooksView(APIView):
    def get(self,request):
        books = models.Book.objects.all()
        books_ser = BookModelSerializer(books,many=True)
        return Response(books_ser.data)

    def post(self,request):
        books_ser = BookModelSerializer(data=request.data)
        if books_ser.is_valid():
            books_ser.save()
            return Response(books_ser.data)
        else:
            return  Response(books_ser.errors)
        
        
        
class BookView(APIView):
    def get(self,request,pk):
        book = models.Book.objects.filter(pk=pk).first()
        book_ser = BookModelSerializer(book)
        return Response(book_ser.data)
    def put(self,request,pk):
        book = models.Book.objects.filter(pk=pk).first()
        book_ser = BookModelSerializer(instance=book,data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.data)
        else:
            return Response(book_ser.errors)

    def delete(self,request,pk):
        models.Book.objects.filter(pk=pk).delete()
        return Response({‘status‘:‘删除成功‘})

基于GenericAPIView的视图

  • 添加了通用的模型类 queryset = None;

  • 通用的序列化器 serializer_class = None

  • 与APIView相比简化了代码,通过GenericAPIView类中定义的三个方法可以方便的取数据及序列化器。其他方法书写方法基本一致

  • GenericAPIView源码分析

GenericAPIView继承了APIView

在GenericAPIView内部添加了通用的模型类及通用的序列化器

在视图类中:

  • get_queryset() # 获取queryset对象,用于查询多条数据
queryset = self.queryset
就是自定义视图类中的queryset

技术图片

  • get_object() # 获取一条对象数据

源码分析待定

  • get_serializer(*args, **kwargs) # 获取序列化器对象

在get_serializer(*args, **kwargs)内部调用了get_serializer_class方法,该方法返回了自定义视图类中定义的序列化类,最后在get_serializer返回了自定义序列化类的对象。

技术图片

  • 实际代码
# 基于GenericAPIView的视图
from rest_framework.generics import GenericAPIView
class Books1View(GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    def get(self,request):
        books_list = self.get_queryset()
        books_ser = self.get_serializer(books_list,many=True)
        return Response(books_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(book_ser.errors)
class Book1View(GenericAPIView):
    queryset = models.Book.objects
    serializer_class = BookModelSerializer
    def get(self,request,pk):
        book = self.get_object()
        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(book_ser.errors)

    def delete(self,request,pk):
        self.get_object().delete()
        return Response(‘删除!‘)

基于GenericAPIView及五个扩展类

  • 基于GenericAPIView类的视图类与基于APIView类的视图类除了有通用的模型类以及序列化类,其余方法基本是一致的,还是需要自己来写视图类中的方法,因此rest_framework提供了五个扩展类,帮助我们减少代码量

  • 五个扩展类

 ListModelMixin,CreateModelMixin,UpdateModelMixin,
DestroyModelMixin,RetrieveModelMixin
  • 这五个扩展类需要与GenericAPIView搭配使用,原因可以通过源码解读,以ListModelMixin扩展类为例

在该扩展类中只定义了一个list方法,该方法是获取所有数据的方法,但是在该方法内部需要获取序列化器,但是该扩展类并没有继承任何父类,因此该扩展类的对象现需要在其他父类中寻找能够找到序列化类的这样的类,刚好GenericAPIView中定义了get_serializer()方法

!技术图片

这五种扩展类提供了几种后端视图(对数据资源进行曾删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。

ListModelMixin:

内部需要get_serializer()方法

提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码。 该Mixin的list方法会对数据进行过滤和分页。

CreateModelMixin:

内部需要get_serializer()方法

更新数据的校验是否通过.is_valid()方法

提供create(request, *args, **kwargs)方法快速实现创建资源的视图,成功返回201状态码。 如果序列化器对前端发送的数据验证失败,返回400错误。

UpdateModelMixin:

内部需要get_serializer()方法

更新数据的校验是否通过.is_valid()方法

获取单个数据的get_object()方法

提供update(request, *args, **kwargs)方法,可以快速实现更新一个存在的数据对象。

同时也提供partial_update(request, *args, **kwargs)方法,可以实现局部更新。

成功返回200,序列化器校验数据失败时,返回400错误。

DestroyModelMixin:

获取单个数据的get_object()方法

提供destroy(request, *args, **kwargs)方法,可以快速实现删除一个存在的数据对象。

成功返回204,不存在返回404。

RetrieveModelMixin:

获取单个数据的get_object()方法

内部需要get_serializer()方法

提供retrieve(request, *args, **kwargs)方法,可以快速实现返回一个存在的数据对象。 如果存在,返回200, 否则返回404。

  • 代码
# 基于GenericAPIView及五个扩展类的视图
from rest_framework.mixins import ListModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin
class Books2View(GenericAPIView,ListModelMixin,CreateModelMixin):
    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    def get(self,request):
        return self.list(request)
    def post(self,request):
        return self.create(request)

class Book2View(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    queryset = models.Book.objects
    serializer_class = BookModelSerializer
    def get(self,request,pk):
        return self.retrieve(request)
    def put(self,request,pk):
        return self.update(request)
    def delete(self,request,pk):
        return self.destroy(request)

基于GenericAPIView的9个视图子类

from rest_framework.generics import ListAPIView,UpdateAPIView,DestroyAPIView,RetrieveAPIView,CreateAPIView,RetrieveUpdateAPIView,RetrieveDestroyAPIView,RetrieveUpdateDestroyAPIView,ListCreateAPIView

每个类都同时继承了GenericAPIView以及对应的五个扩展类,每个类都实现指定接口

每个子类只能实现部分接口功能

# 获取所有书籍接口
class Books3View(ListAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer

视图集Viewset

基于GenericAPIView及五个扩展类的视图中d代码量相较于继承APIView的视图缩减了很多,但是还是需要写俩个类来区分两个get方法,因此drf提供了ViewSet.使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中.

  • list() 提供一组数据
  • retrieve() 提供单个数据
  • create() 创建数据
  • update() 保存数据
  • destory() 删除数据

ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。

视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上。如:

class BookInfoViewSet(viewsets.ViewSet):

    def list(self, request):
        books = BookInfo.objects.all()
        serializer = BookInfoSerializer(books, many=True)
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        try:
            books = BookInfo.objects.get(id=pk)
        except BookInfo.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
        serializer = BookInfoSerializer(books)
        return Response(serializer.data)

在设置路由时,我们可以如下操作:

urlpatterns = [
    url(r‘^books/$‘, BookInfoViewSet.as_view({‘get‘:‘list‘}),
    url(r‘^books/(?P<pk>\d+)/$‘, BookInfoViewSet.as_view({‘get‘: ‘retrieve‘})

常用的视图集父类

  • ViewSet

继承自APIViewViewSetMixin,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。

ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典(如{‘get’:’list’})的映射处理工作。

在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。

  • GenericViewSet

使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与GenericAPIView,所以还需要继承GenericAPIView

GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIViewViewSetMixin,在实现了调用as_view()时传入字典(如{‘get‘:‘list‘})的映射处理工作的同时,还提供了GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用。

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

继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

from rest_framework.viewsets import ModelViewSet
class Book4View(ModelViewSet):
    queryset = models.Book.objects
    serializer_class = BookModelSerializer


# 基于modelviewset
re_path(r‘^books4/‘,views.Book4View.as_view({‘get‘:‘list‘,‘post‘:‘create‘})),
re_path(r‘^book4/(?P<pk>\d+)‘,views.Book4View.as_view({‘put‘:‘update‘,‘delete‘:‘destroy‘,‘get‘:‘retrieve‘})),
  • ReadOnlyModelViewSet

继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin。

ViewSetMixin源码阅读

# ViewSetMixin提供了as_view()方法,且配合url的actions参数,可以实现请求方式的动态指定分配

# 核心代码(所以路由中只要配置了对应关系,比如actions={‘get‘:‘list‘}),当get请求来,就会执行list方法
def view(request, *args, **kwargs):
    self = cls(**initkwargs)
    self.action_map = actions
    for method, action in actions.items():
		# method:get, action:list
        handler = getattr(self, action)
         # 执行完上一句,handler就变成了list的内存地址
        setattr(self, method, handler)
        # 执行完上一句  对象.get=list
		# for循环执行完毕 对象.get:对着list   对象.post:对着create
        
# 等url匹配成功后,通过dispatch反射调用请求方法时,执行替换后的list,create等方法

ViewSetMixin & APIView

# 基于ViewSetMixin的视图类和APIView编写接口
# 利用ViewSetMixin的as_view()方法,在url中通过actions分配请求处理的方法
# 因为仅使用APIView,所有需要自己实现接口功能
# 自定制化强,可控性高

# 代码:
# views.py
from rest_framework.viewsets import ViewSetMixin
class BookViewSetMixin(ViewSetMixin, APIView):	
    # ViewSetMixin一定要放在第一个父类位置,才能使用到ViewSetMixin的as_views()
    
    def get_all_book(self,request):
        book_list = models.Book.objects.all()
        book_ser = ser.BookModelSerializer(book_list, many=True)
        return Response(book_ser.data)
    
# urls.py:指定处理get请求的视图方法
url(r‘books5/$‘, views.BookViewSetMixin.as_view(actions={‘get‘: ‘get_all
                                                         

rest_framework视图家族

标签:https   first   图片   管理   不能   containe   ror   写视图   前端   

原文地址:https://www.cnblogs.com/Kathrine/p/13340915.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!