• 十大接口和六大接口、视图集


    准备工作:

    models.py

    from django.db import models
    
    # 基类:是抽象的(不会完成数据库迁移),目的是提供共有字段的
    class BaseModel(models.Model):
        is_delete = models.BooleanField(default=False)
        updated_time = models.DateTimeField(auto_now_add=True)
    
        class Meta:
            abstract = True  # 必须完成该配置
    
    class Book(BaseModel):
        name = models.CharField(max_length=64)
        price = models.DecimalField(max_digits=5, decimal_places=2, null=True)
        image = models.ImageField(upload_to='img', default='img/default.png')
    
        publish = models.ForeignKey(to='Publish', related_name='books', db_constraint=False, on_delete=models.DO_NOTHING)
        authors = models.ManyToManyField(to='Author', related_name='books', db_constraint=False)
    
        @property  # @property字段默认就是read_only,且不允许修改
        def publish_name(self):
            return self.publish.name
    
        @property  # 自定义序列化过程
        def author_list(self):
            temp_author_list = []
            for author in self.authors.all():
                author_dic = {
                    "name": author.name
                }
                try:
                    author_dic['phone'] = author.detail.phone
                except:
                    author_dic['phone'] = ''
                temp_author_list.append(author_dic)
            return temp_author_list
    
    
    
    class Publish(BaseModel):
        name = models.CharField(max_length=64)
    
    
    class Author(BaseModel):
        name = models.CharField(max_length=64)
    
    
    class AuthorDetail(BaseModel):
        phone = models.CharField(max_length=11)
        author = models.OneToOneField(to=Author, related_name='detail', db_constraint=False, on_delete=models.CASCADE)
    View Code

    serializers.py

    from rest_framework import serializers
    from . import models
    
    # 只有在资源需要提供群改,才需要定义ListSerializer,重写update方法
    class BookListSerializer(serializers.ListSerializer):
        def update(self, queryset, validated_data_list):
            return [
                self.child.update(queryset[index], validated_data) for index, validated_data in enumerate(validated_data_list)
            ]
    
    class BookModelSerializer(serializers.ModelSerializer):
        class Meta:
            list_serializer_class = BookListSerializer
            model = models.Book
            fields = ['name', 'price', 'image', 'publish', 'authors', 'publish_name', 'author_list']
            extra_kwargs = {
                'publish': {
                    'write_only': True
                },
                'authors': {
                    'write_only': True
                }
            }

    基于GenericAPIView的十大接口

    views.py

    from rest_framework.generics import GenericAPIView
    from rest_framework import mixins
    from . import models,serializers
    from rest_framework.response import Response
    # 十大接口 # 1) 单查、群查、单增、单整体改、单局部改都可以直接使用 # 2) 单删不能直接使用,因为默认提供的功能是删除数据库数据,不是我们自定义的is_delete字段值的修改 # 3) 除了群查以外的接口,都要自己实现 class BookV1APIView(GenericAPIView, mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin): queryset = models.Book.objects.filter(is_delete=False).all() serializer_class = serializers.BookModelSerializer def get(self, request, *args, **kwargs): if 'pk' in kwargs: return self.retrieve(request, *args, **kwargs) # 单查 # queryset = models.Book.objects.filter(is_delete=False).all() # 注:给序列化类context赋值{'request': request},序列化类就可以自动补全后台图片链接 # serializer = serializers.BookModelSerializer(queryset, many=True, context={'request': request}) # return Response(serializer.data) return self.list(request,*args,**kwargs) # 群查 def post(self, request, *args, **kwargs):
          if not isinstance(request.data,list): return self.create(request, *args, **kwargs) # 单增 serializer = self.get_serializer(data=request.data,many=True) serializer.is_valid(raise_exception=True) objs = serializer.save() return Response(serializer.BookModelSerializer(objs,many=True).data,status=200) # 群增 """ 单删:接口:/books/(pk)/ 群删:接口:/books/ 数据:[pk1, ..., pkn] """ def delete(self, request, *args, **kwargs): pk = kwargs.get('pk') if pk: pks = [pk] # 将单删伪装成群删一条 else: pks = request.data # 群删的数据就是群删的主键们 try: # request.data可能提交的是乱七八糟的数据,所以orm操作可能会异常 rows = models.Book.objects.filter(is_delete=False, pk__in=pks).update(is_delete=True) except: return Response(status=400) if rows: # 只要有受影响的行,就代表删除成功 return Response(status=204) return Response(status=400) def put(self,request,*args,**kwargs): # 单整体改 if 'pk' in kwargs: return self.update(request,*args,**kwargs) # 群整体改 pks = [] try: # 只要不是要求的标准数据,一定会在下方四行代码某一行抛出异常 for dic in request.data: pks.append(dic.pop('pk')) objs = models.Book.objects.filter(is_delete=False, pk__in=pks) assert len(objs) == len(request.data) # 两个列表长度必须一致 except: return Response(status=400) # 序列化类同时赋值instance和data,代表用data重新更新instance => 修改 serializer = serializers.BookModelSerializer(instance=objs, data=request.data, many=True) serializer.is_valid(raise_exception=True) objs = serializer.save() # 为什么要将新增的对象重新序列化给前台,因为序列化与反序列化数据不对等 return Response(serializers.BookModelSerializer(objs, many=True).data) def patch(self,request,*args,**kwargs): # 单局部改 if 'pk' in kwargs: return self.partial_update(request,*args,**kwargs) # 群局体改 pks = [] try: for dic in request.data: pks.append(dic.pop('pk')) objs = models.Book.objects.filter(is_delete=False, pk__in=pks) assert len(objs) == len(request.data) except: return Response(status=400) # partial=True就是将所有反序列化字段的 required 设置为 False(提供就校验,不提供不校验) serializer = serializers.BookModelSerializer(instance=objs, data=request.data, many=True,partial=True) serializer.is_valid(raise_exception=True) objs = serializer.save() return Response(serializers.BookModelSerializer(objs, many=True).data)

    基于generics包下工具视图类的六大基础接口

    views.py

    '''
    六大基础接口
    1)直接继承generics包下的工具视图类,可以完成六大基础接口
    2)单查群查不能共存
    3)单删一般会重写
    '''
    
    from rest_framework import generics
    class BookV2APIView(generics.ListAPIView,
                        generics.RetrieveAPIView,
                        generics.CreateAPIView,
                        generics.UpdateAPIView,
                        generics.DestroyAPIView):
        queryset = models.Book.objects.filter(is_delete=False).all()
        serializer_class = serializers.BookModelSerializer
    
        def get(self, request, *args, **kwargs):
            if 'pk' in kwargs:
                return self.retrieve(request, *args, **kwargs)
            return self.list(request, *args, **kwargs)

    视图集

    前言

    """ ViewSetMixin类存在理由推导
    1)工具视图类,可以完成六大基础接口,唯一缺点是单查与群查接口无法共存
        (只配置queryset、serializer_class、lookup_field)
    2)不能共存的原因:RetrieveAPIView和ListAPIView都是get方法,不管带不带pk的get请求,只能映射给一个get方法
    3)能不能修改映射关系:
        比如将/books/的get请求映射给list方法,
        将/books/(pk)/的get请求映射给retrieve方法,
        甚至可以随意自定义映射关系
    """
    
    """ 继承视图集的视图类的as_view都是走ViewSetMixin类的,核心源码分析
    @classonlymethod
    def as_view(cls, actions=None, **initkwargs):
        # ...
    
        # 没有actions,也就是调用as_view()没有传参,像as_view({'get': 'list'})
        if not actions:
            raise TypeError("The `actions` argument must be provided when "
                            "calling `.as_view()` on a ViewSet. For example "
                            "`.as_view({'get': 'list'})`")
    
            # ...
    
        # 请求来了走view函数
        def view(request, *args, **kwargs):
            # ...
            # 解析actions,修改 请求分发 - 响应函数 映射关系
            self.action_map = actions
            for method, action in actions.items():  # method:get | action:list
                handler = getattr(self, action)  # 从我们视图类用action:list去反射,所以handler是list函数,不是get函数
                setattr(self, method, handler)  # 将get请求对应list函数,所以在dispath分发请求时,会将get请求分发给list函数
    
                # ...
                # 通过视图类的dispatch完成最后的请求分发
                return self.dispatch(request, *args, **kwargs)
    
            # ...
            # 保存actions映射关系,以便后期使用
            view.actions = actions
            return csrf_exempt(view)
    """

    视图集的使用总结

    1)可以直接继承ModelViewSet,实现六大继承接口(是否重写destroy方法,或其他方法,根据需求决定)
    2)可以直接继承ReadOnlyModelViewSet,实现只读需求(只有单查群查)
    3)继承ViewSet类,与Model类关系不是很密切的接口:登录的post请求,是查询操作;短信验证码发生接口,借助第三方平台
    4)继承GenericViewSet类,就代表要配合mixins包,自己完成任意组合
    5)继承以上4个视图集任何一个,都可以与路由as_view({映射})配合,完成自定义请求响应方法

    urls.py

    url(r'^v3/books/$', views.BookV3APIView.as_view(
        {'get': 'list', 'post': 'create', 'delete': 'multiple_destroy'}
        )),
    
    url(r'^v3/books/(?P<pk>d+)/$', views.BookV3APIView.as_view(
            {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'}
        )),

    views.py

    from rest_framework.viewsets import ModelViewSet
    from rest_framework.response import Response
    class BookV3APIView(ModelViewSet):
        queryset = models.Book.objects.filter(is_delete=False).all()
        serializer_class = serializers.BookModelSerializer
    
        # 可以在urls.py中as_view({'get': 'my_list'})自定义请求映射
        def my_list(self, request, *args, **kwargs):
            return Response('ok')
    
        # 需要完成字段删除,不是重写delete方法,而是重写destroy方法
        def destroy(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            models.Book.objects.filter(is_delete=False, pk=pk).update(is_delete=True)
            return Response(status=204)
    
    
        # 群删接口
        def multiple_destroy(self, request, *args, **kwargs):
            try:
                models.Book.objects.filter(is_delete=False, pk__in=request.data).update(is_delete=True)
            except:
                return Response(status=400)
            return Response(status=204)
  • 相关阅读:
    C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本
    C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本
    C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本
    C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本
    《程序员,你伤不起》 回答热心爸爸读者的疑问
    入驻微信公众号平台【今日热点在线】、【大数据躺过的坑】和【九哥九嫂小日子】,欢迎关注
    入驻百家号【九哥聊IT】和【九哥九嫂小日子】,欢迎关注
    全网最详细的最新稳定OSSEC搭建部署(ossec-server(CentOS7.X)和ossec-agent(CentOS7.X))(图文详解)
    CentOS 7的安装详解
    全网最全的Windows下Anaconda2 / Anaconda3里正确下载安装爬虫框架Scrapy(离线方式和在线方式)(图文详解)
  • 原文地址:https://www.cnblogs.com/baohanblog/p/12354203.html
Copyright © 2020-2023  润新知