十大接口与视图家族

十大接口与视图家族

1、序列化类外键字段的覆盖

1、在序列化类中自定义字段,名字与model类中属性名一致,称之为覆盖(覆盖的是属性的所有规则:extra_kwargs中的、model字段提供的默认的、数据库唯一约束等校验规则)

2、外键覆盖字段用PrimaryKeyRelatedField来实现,可以做到只读、只写、可读可写三种

  • 只读:read_only = True

  • 只写:queryset = 关联表的queryset,write_only

  • 可读可写:queryset = 关联表的queryset

3、当外界关联的数据有多个时,需要标识many = True

class BookModelSerializer(serializers.ModelSerializer):
    # 如何覆盖外键字段
    # publish = serializers.PrimaryKeyRelatedField(read_only=True)  # 只读
    # publish = serializers.PrimaryKeyRelatedField(queryset=models.Publish.objects.all(), write_only=True)  # 只写
    # publish = serializers.PrimaryKeyRelatedField(queryset=models.Publish.objects.all())  # 可读可写
​
    publish = serializers.PrimaryKeyRelatedField(queryset=models.Publish.objects.all())
    authors = serializers.PrimaryKeyRelatedField(queryset=models.Author.objects.all(), many=True)
​
    class Meta:
        model = models.Book
        fields = ('name', 'price', 'image', 'publish', 'authors')

2、十大接口序列化

    # Baseserializer类中各参数含义
    def __init__(self, instance=None, data=empty, **kwargs):
        pass
  • instance:对象类型赋值给instance

  • data:请求来的数据赋值给data

  • kwargs:内部有三个属性:many、partial、context

    • many:操作对象或数据时有多个时many=True

    • partial:在修改需求时校验所有的字段required=False时使用partial=True

    • context:用于视图类和序列化类直接传参使用

1、初始化序列化类,设置partial = True可以将所有的反序列化字段required设置为False(提供就校验,不提供就不校验),可以在局部修改接口的时候使用

2、初始化序列化类,设置context = {...},在序列化类操作self.context,实现视图类和序列化类数据互通

3、只有要完成资源群改这种需求的时候,才需要自定义ListSerializer绑定给自定义的ModelSerializer,重写update方法来实现需求

六个必备接口:单查、群查、单增、单删、单整体改、单局部改

四个额外接口(了解):群增、群删、群整体改、群局部改

1、单查、群查

单查接口:/books/pk/

群查接口:/books/

class BookAPIView(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        # 单查,未删除的
        if pk:
            obj = models.Book.object.filter(is_delete=False,pk=pk).first()
            serializer = serializers.BookModelSerializer(instance=obj)
            # 此处的APIResponse是自定义的二次封装的Response
            return APIResponse(result=serializer.data)
        # 群查
        else:
            queryset = models.Book.object.filter(is_delete=False).all()
            serializer = serializers.BookModelSerializer(instance=queryset, many=True)
            return APIResponse(results=serializer.data)

2、单增、群增

单增接口:/books/ 数据:dict

群增接口:/books/ 数据:list

区分是单增还是群增就是判断request.data是dict还是list

def post(self, request, *args, **kwargs):
    # 单增
    if not isinstance(request.data, list):
        serialiazer = serializer.BookModelSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)  # 校验失败直接抛异常
        obj = serialiazer.save()  # 存入数据库中
        return APIResponse(result=serializer.BookModelSerializer(obj).data, http_status=201)
    else:
        # 群增
        serialiazer = serializer.BookModelSerializer(data=request.data, many=True)
        serializer.is_valid(raise_exception=True)  # 校验失败直接抛异常
        objs = serialiazer.save()  # 存入数据库中
        return APIResponse(result=serializer.BookModelSerializer(objs, many=True).data, http_status=201)

3、单删、群删

单删群删接口不需要利用序列化,可以直接操作数据库

单删接口:/books/pk/

群删接口:/books/ 数据:[pk1, ...., pkn]

    def delete(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            pks = [pk]  # 单删伪装成群删一条
        else:
            pks = request.data  # 群删的数据就是群删的主键们
        try:
            rows = models.Book.objects.filter(is_delete=False, pk__in=pks).update(is_delete=True)
        except:
            # 如果传的request.data提交的数据乱七八糟的,ORM操作就会异常
            return APIResponse(1, '数据有误')
        if rows:  # 受影响行数,只要有就删除成功
            return APIResponse(0, '删除成功')
        # 如果传的都是已经删除过的,没有受影响行数就会删除失败
        return APIResponse(2, '删除失败')

4、单整体改、群整体改

单整体改接口:/books/pk/ 数据:dict

群整体改接口:/books/ 数据:[{pk:1, ...}, ..., {pk:n, ...}] 或者 {pks: [pk1, ..., pkn], data: [{}, ..., {}]}一般都用第一种

    
def put(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:  #
            try:
                instance = models.Book.objects.get(is_delete=False, pk=pk)
            except:
                return APIResponse(1, 'pk error', http_status=400)
            # 序列化类同时赋值instance和data,代表用data重新更新instance => 修改
            serializer = serializers.BookModelSerializer(instance=instance, data=request.data)
            serializer.is_valid(raise_exception=True)
            obj = serializer.save()
            return APIResponse(result=serializers.BookModelSerializer(obj).data)
        else:  #
            """ 分析request.data数据 [{'pk':1, 'name': '', 'publish': 1, 'authors': [1, 2]}, ...]
            1)从 request.data 中分离出 pks 列表
            2)pks中存放的pk在数据库中没有对应数据,或者对应的数据已经被删除了,这些不合理的pk要被剔除
            3)pks最终转换得到的 objs 列表长度与 request.data 列表长度不一致,就是数据有误
            """
            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 APIResponse(1, '数据有误', http_status=400)
​
            serializer = serializers.BookModelSerializer(instance=objs, data=request.data, many=True)
            serializer.is_valid(raise_exception=True)
            objs = serializer.save()
            return APIResponse(result=serializers.BookModelSerializer(objs, many=True).data)

5、单局部改、群局部改

跟单整体改和群整体改一样,只不过加了一个partial=True

单局部改接口:/books/pk/ 数据:dict

群局部改接口: /books/ 数据:[{pk:1, ...}, ..., {pk:n, ...}] 或者 {pks: [pk1, ..., pkn], data: [{}, ..., {}]}一般都用第一种

def put(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:  #
            try:
                instance = models.Book.objects.get(is_delete=False, pk=pk)
            except:
                return APIResponse(1, 'pk error', http_status=400)
            # 序列化类同时赋值instance和data,代表用data重新更新instance => 修改
            serializer = serializers.BookModelSerializer(instance=instance, data=request.data)
            serializer.is_valid(raise_exception=True)
            obj = serializer.save()
            return APIResponse(result=serializers.BookModelSerializer(obj).data)
        else:  #
            """ 分析request.data数据 [{'pk':1, 'name': '', 'publish': 1, 'authors': [1, 2]}, ...]
            1)从 request.data 中分离出 pks 列表
            2)pks中存放的pk在数据库中没有对应数据,或者对应的数据已经被删除了,这些不合理的pk要被剔除
            3)pks最终转换得到的 objs 列表长度与 request.data 列表长度不一致,就是数据有误
            """
            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 APIResponse(1, '数据有误', http_status=400)
​
            serializer = serializers.BookModelSerializer(instance=objs, data=request.data, many=True)
            serializer.is_valid(raise_exception=True)
            objs = serializer.save()
            return APIResponse(result=serializers.BookModelSerializer(objs, many=True).data)

3、视图家族

视图基类:APIView、GenericAPIView

视图工具类:mixins包下的五个类(六个方法)

工具视图类:generics包下的所有GenericAPIView的子类

视图集:viewsets包下的类

1、GenericAPIView基类

基本不会单独使用,是高级视图类的依赖基础

  1. GenericAPIView继承了APIView所有的APIView子类写法再继承GenericAPIView时可以保存一致

  2. GenericAPIView给我们提供了三个属性queryset、serializer_class、lookup_field

  3. GenericAPIView给我们提供了三个方法get_queryset、get_serializer、get_obj

2、mixins包存放了视图工具类(不能单独使用,必须配合GenericAPIView使用)

CreateModelMixin:单增工具类 create方法

RetrieveModelMixin:单查工具类 retrieve方法

ListModelMixin:群查工具类 list方法

UpdateModelMixin:单整体局部改工具类 update方法

DestroyModelMixin:单删工具类 destory方法

3、generic包下的所有GenericAPIView的子类

就是继承GenericAPIView和不同的mixins下的工具类的组合

1、定义的视图类,继承generic包下已有的特点GenericAPIView子类,可以在只初始化queryset和serializer_class两个类属性后,就获取特点的功能

2、定义的视图类,自己继承GenericAPIView基类,再任意组合mixins包下的一个或多个工具类,可以实现自定义的工具视图类,获取特点的功能或功能们

注意:

  1. 在这些模式下,不能实现单查和群查共存,但是可以加逻辑区分,也可以用视图集

  2. DestroyModelMixin工具类提供的destory方法默认是从数据库中删除数据,所以一般删除数据的需求都是自定义逻辑

# ----------------------------- 过渡写法:了解 -----------------------------
from rest_framework.generics import GenericAPIView
class BookV1APIView(GenericAPIView):
    # 将数据和序列化提升为类属性,所有的请求方法都可以复用
    queryset = models.Book.objects.filter(is_delete=False).all()  # ORM优化机制一次只能取出21条数据
    serializer_class = serializers.BookModelSerializer
    lookup_field = 'pk'  # 可以省略,默认是pk,与url有名分组对应的
# 群查
    def get(self, request, *args, **kwargs):
        # queryset = models.Book.objects.filter(is_delete=False).all()  # => 方法+属性两行代码
        queryset = self.get_queryset()
        # serializer = serializers.BookModelSerializer(instance=queryset, many=True)  # => 方法+属性两行代码
        serializer = self.get_serializer(instance=queryset, many=True)
        return APIResponse(results=serializer.data)
​
    # 单查
    # def get(self, request, *args, **kwargs):
    #     obj = self.get_object()
    #     serializer = self.get_serializer(obj)
    #     return APIResponse(results=serializer.data)
# 单增
    def post(self, request, *args, **kwargs):
        # serializer = serializers.BookModelSerializer(data=request.data)
        serializer = self.get_serializer(data=request.data)  # 同样的步骤多了,好处就来了
        serializer.is_valid(raise_exception=True)
        obj = serializer.save()
        return APIResponse(result=self.get_serializer(obj).data, http_status=201)
    
# ----------------------------- 过渡写法:了解 -----------------------------
from rest_framework.generics import GenericAPIView
from rest_framework import mixins
class BookV2APIView(GenericAPIView, mixins.RetrieveModelMixin, mixins.CreateModelMixin):
    queryset = models.Book.objects.filter(is_delete=False).all()
    serializer_class = serializers.BookModelSerializer
​
    # 单查
    def get(self, request, *args, **kwargs):
        # obj = self.get_object()
        # serializer = self.get_serializer(obj)
        # return APIResponse(results=serializer.data)
# return self.retrieve(request, *args, **kwargs)
​
        response = self.retrieve(request, *args, **kwargs)
        return APIResponse(result=response.data)
​
    # 单增
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
​
​
# ----------------------------- 开发写法:常用 -----------------------------
from rest_framework.generics import RetrieveAPIView
class BookV3APIView(RetrieveAPIView):
    queryset = models.Book.objects.filter(is_delete=False).all()
    serializer_class = serializers.BookModelSerializer
​
    # 单查
    pass

 

 

posted @ 2020-02-21 20:50  Mr沈  阅读(676)  评论(0编辑  收藏  举报