DRF - 视图组件

视图组件


70061675672727_.pic_hd

0、APIView与Django原生的View类的区别

1.APIView中传入视图方法中的Request对象

是REST framework的Request对象

而不是Django的HttpRequest对象

2.视图方法可以返回REST framework的Response对象(使用的是drf的Response对象)

3.任何APIException异常都会被捕获到,并且处理成合适的响应信息

4.在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制

1、两个视图基类

0.APIView类的属性

APIView类属性名称 作用
renderer_classes 响应格式
parser_classes 能够解析的请求格式
authentication_classes 认证类
throttle_classes 频率类
permission_classes 权限类

1.视图基类:APIView

APIView+ModelSerializer+Resposne写5个接口

(1)视图基于APIView + Response

class BookView(APIView):
    def get(self, request):
        books = Book.objects.all()
        ser = BookSerializer(instance=books, many=True)
        return Response(ser.data)

    def post(self, request):

        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            # 咱们只有ser序列化类的对象,但是咱们想要的是新增的数据对象,然后序列化成字典。
            # 但是,大前提是序列化类中新增的create方法一定要返回新增的对象,
            # 虽然我们没有写create方法,但是在ModelSerializer类中create方法,返回了新增了数据对象
            return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})


class BookDetailView(APIView):
    # 查询单条
    def get(self, request, pk):
        books = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=books)
        return Response(ser.data)

    # 修改
    def put(self, request, pk):
        books = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=books, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})

    # 删除
    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response({'code': 100, 'msg': '删除成功'})

(2)序列化类 基于ModelSerializer

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
        extra_kwargs = {'name': {'max_length': 8},
                        'publish_detail': {'read_only': True},
                        'author_list': {'read_only': True},
                        'publish': {'write_only': True},
                        'authors': {'write_only': True},
                        }

(3)路由

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', views.BookView.as_view()),
    path('books/<int:pk>/', views.BookDetailView.as_view()),
]

2.视图基类GenericAPIView

GenericAPIView继承了APIView有很多新的属性和方法

(1)视图类中基于 GenericAPIView 来写接口

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

    def get(self, request):
        # 如果通过get_queryset我们可以重写,扩展性更高
        objs = self.get_queryset()
        # 可以通过重写get_serializer_class来控制哪个序列化类来做序列化
        ser = self.get_serializer(instance=objs, many=True)
        return Response(ser.data)

    def post(self, request):
        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            ser.save()
            # 咱们只有ser序列化类的对象,但是咱们想要的是新增的数据对象,然后序列化成字典。
            # 但是,大前提是序列化类中新增的create方法一定要返回新增的对象,
            # 虽然我们没有写create方法,但是在ModelSerializer类中create方法,返回了新增了数据对象
            return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})


class BookDetailView(GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # 查询单条
    def get(self, request, pk):
        books = self.get_object()
        ser = BookSerializer(instance=books)
        return Response(ser.data)

    # 修改
    def put(self, request, pk):
        books = self.get_object()
        ser = self.get_serializer(instance=books, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})

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

3.基于GenericAPIView与5个视图拓展类

(1)GenericAPIView的属性和方法

  • 属性

1)queryset:要序列化或者反序列化的表模型数据

2)serializer_class 使用的序列化类

3)lookup_field 查询单条的路由分组出来的字段名

4)filter_backends 过滤类的配置

5)pagination_class 分页器的配置

  • 方法

1)get_queryset 获取要序列化的对象

2)get_object 获取单个对象

3)get_serializer 获取序列化类,跟它差不多的get_serializer_class 一般重写

4)filter_queryset 过滤有关系

genericAPIView()

(2)5个视图拓展类

GenericAPIView封装了5个视图拓展类,分别对应5个接口

  • get请求 查询所有:ListModelMixin-->list方法
  • get请求 查询一个:RetrieveModelMixin-->Retrieve方法
  • post请求 新增一个:CreateModelMixin-->Create方法
  • put请求 修改一个:UpdateModelMixin-->Update方法
  • delete请求 删除一个:DestroyModelMixin-->Destroy方法

在5个视图类中,封装的不是get方法或者post方法,虽然名字不叫get方法或者post方法,但是和其内容一致

所以必须要配合 GenericAPIView 视图基类来使用,不然会报错

1.views.py中编写视图类

基于GenericAPIView封装的5个视图拓展类编写

from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, \
    ListModelMixin


class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request):
        return self.list(request)

    def post(self, request):
        return self.create(request)


class BookDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    # 查询单条
    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)

2.序列化类

class BookSerializer(serializers.ModelSerializer):
    # 跟表有关联
    class Meta:
        model = Book
        fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
        extra_kwargs = {'name': {'max_length': 8},
                        'publish_detail': {'read_only': True},
                        'author_list': {'read_only': True},
                        'publish': {'write_only': True},
                        'authors': {'write_only': True},
                        }

3.路由

urlpatterns = [
    path('books/', views.BookView.as_view()),
    path('books/<int:pk>/', views.BookDetailView.as_view()),
]

2、9个视图子类

9个视图子类,不需要额外继承GenericAPIView,只要继承9个中其中某个,就会有某个或某几个接口

1.9个视图子类对应的请求与功能

视图子类 请求 功能
CreateAPIView post 新增
ListAPIView get 查询所有
RetrieveAPIView get 查询一个
DestroyAPIView delete 删除
UpdateAPIView put、patch 修改
ListCreateAPIView get、post 查询所有、新增
RetrieveUpdateAPIView get、put、patch 查询一个、修改
RetrieveDestroyAPIView get、delete 查询一个、删除
RetrieveUpdateDestroyAPIView get、put、patch、delete 查询一个、修改、删除

2.基于9个视图子类编写接口

"第四层:基于9个视图子类编写接口"
from rest_framework.generics import ListAPIView, ListCreateAPIView, CreateAPIView, RetrieveAPIView, \
    RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView


# 查询所有 新增一个
class BookView(ListCreateAPIView):  # 查询所有新增一个
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # get 和 post通过继承已经写好了


# 查询一个,修改一个,删除一个
class BookDetailView(RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # get put delete
  • ListCreateAPIView源码

image-20230206203059668

  • RetrieveUpdateDestroyAPIView源码

image-20230206203333916

3.多种混和编写接口

可以通过九个的组合,来实现多种功能的实现

(1)ListAPIView 查询所有, CreateAPIView 新增一个

(2)ListAPIView + CreateAPIView = ListCreateAPIView

(3)RetrieveAPIView 查询一个 , DestroyAPIView 删除 , UpdateAPIView 修改

(4)RetrieveDestroyAPIView 查找一个和删除 RetrieveUpdateAPIView查找一个和修改,但是不存在Destroy和Update的组合

(5)RetrieveUpdateDestroyAPIView 查询一个、修改、删除

3、视图集

第五层。五个接口还是需要写两个视图类,配置两条路由

  • 但是两个视图类写成一个,
    • 路由不同
    • 会有两个get方法
  • drf中的类 ModelViewSet 只要继承他,5个接口都有,但是路由写法变了

1.通过ModelViewSet类编写5个接口

路由的写法改变了,但是视图类只用写一个

  • 路由
# 路由
urlpatterns = [
    path('books/', views.BookView.as_view({'get': 'list', 'post': 'create'})),
    path('books/<int:pk>/', views.BookView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
]
  • 视图类
class BookView(ModelViewSet):  # 查询所有,新增一个
    queryset = Book.objects.all()
    serializer_class = BookSerializer

2.通过ReadOnlyModelViewSet编写只读接口

  • 路由
urlpatterns = [
    path('books/', views.BookView.as_view({'get': 'list'})),
    path('books/<int:pk>/', views.BookView.as_view({'get': 'retrieve'})),
]
  • 视图类
class BookView(ReadOnlyModelViewSet):  # 查询所有,新增一个
    queryset = Book.objects.all()
    serializer_class = BookSerializer

4.from rest_framework.viewsets包下的类

1.ModelViewSet - 路由写法变了,只需要写两行,5个接口都有

  • 5个视图扩展类
  • ViewSetMixin
  • GenericAPIView

2.ReadOnlyModelViewSet - 路由写法变了,只需要写两行,2个只读接口都有

  • 2个视图扩展类

  • ViewSetMixin

  • GenericAPIView

3.ViewSetMixin 魔法类

重写了as_view,所以只要继承ViewSetMixin后,路由的写法都需要变成映射方法

4.ViewSet - 想用APIView

  • ViewSetMixin + APIView

5.GenericViewSet - 想用GenericAPIView

  • ViewSetMixin + GenericAPIView
  • 想继承APIView,但是想改变路由写法并且视图类中方法名可以任意命名,需要继承ViewSet
  • 想继承GenericAPIView,但是想改变路由写法并且视图类中方法名可以任意命名,要继承GenericViewSet

5.路由写法改变的原因

(1)GenericViewSet

GenericViewSet =

导致路由配置改变了形式

view = MyViewSet.as_view({'get': 'list', 'post': 'create'})

(2)ViewSetMixin源码分析

-->属性的查找顺序从左往右,由于ViewSetMixin中有as_view方法,则先执行ViewSetMixin中的as_view方法

posted @ 2023-02-06 21:12  Duosg  阅读(22)  评论(0编辑  收藏  举报