十大接口

十大接口

一、Response响应封装

1.1封装

from rest_framework.response import Response
class APIResponse(Response):
    def __init__(self, status=0, msg="ok", results=None, http_status=None, headers=None, exception=False, **kwargs):
        data_dic = {  # json的response基础有数据状态码和数据状态信息
            "status": status,
            "msg": msg,
        }

        if results is not None:  # 后台有数据,响应数据
            data_dic['results'] = results
        if kwargs:
            data_dic.update(**kwargs)  # 后台的一切自定义响应数据直接放到响应数据data中

        super().__init__(data=data_dic, status=http_status, headers=headers, exception=exception)

        
       

1.2使用

class MyAPIView(APIView):
    def get(self, request, *args, **kwargs):

        pk = kwargs.get("pk")
        if pk:
            book_obj = models.Book.objects.filter(pk=pk).first()
            if not book_obj:               
                return APIResponse(status=1, msg='get error')
            
            book_ser = BookSerializers(book_obj).data
            print(book_ser)           
            return APIResponse(results=book_ser)
        else:

            book_obj = models.Book.objects.all()
            book_list_obj = BookSerializers(book_obj, many=True).data
            print(book_list_obj)
            return APIResponse(results=book_list_obj)

二、ModelSerializer扩展

2.1连表查询

# models.py
class Book(BaseModel):  # 书
    name = models.CharField(max_length=49)
    price = models.DecimalField(max_digits=5, decimal_places=2)

    # 出版社与书是一对多的关系,                设置反向查询字段     断外键之间的关系      设置级联,不进行级联删除(出版社删了,书不删) 一对多关系
    publish = models.ForeignKey(to="Publish", related_name="books", db_constraint=False, on_delete=models.DO_NOTHING)

    # 书与作者是多对多的关系                      断关联

    # 在多对多外键实际在关系表中,ORM默认关系表中两个外键都是级联
    # ManyToManyField字段不提供设置on_delete,如果想设置关系表级联,只能手动定义创建第三张关系表
    author = models.ManyToManyField(to="Author", related_name="books", db_constraint=False)

    # 自定义连表深度,不需要反序列化,因为自定义插拔属性不参与反序列化
    @property
    def publish_name(self):
        return self.publish.name
	# 连表查询
    @property
    def author_list(self):
        temp_author_list = []
        for author in self.author.all():
            temp_author_list.append({
                'name': author.name,
                'sex': author.get_sex_display(),
                'mobile': author.detail.mobile
            })
        return temp_author_list
# serializers.py 序列化类
class BookSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = ("name", "price", "publish_name" ,"author_list")
# views.py
class MyAPIView(APIView):
    # 单查和群查

    def get(self, request, *args, **kwargs):

        pk = kwargs.get("pk")
        if pk:
			# 单挑数据
            book_obj = models.Book.objects.filter(pk=pk, is_delete=False).first()

            if not book_obj:
                return APIResponse(status=1, msg='get error')
			
            book_ser = BookSerializers(book_obj,many=False).data
            print(book_ser)

            return APIResponse(results=book_ser)
        else:

            book_obj = models.Book.objects.all()
			# 全部数据
            book_list_obj = BookSerializers(book_obj, many=True).data
            print(book_list_obj)
            return APIResponse(results=book_list_obj)

总结

  1. 连表查询在modes.py中自定义的字段,一旦其中的逻辑出错,他对应的返回值就不会做出任何响应
  2. 自定义连表深度,不需要反序列化,因为自定义插拔属性不参与反序列化
  3. 子序列化可以辅助快速实现自定义外键深度的序列化,但是不能进行反序化,__all__

img

2.2指定字段

1) 使用fields来明确字段, __all__ 表名包含所有字段,也可以写明具体哪些字段,如
class BookInfoSerializer(serializers.ModelSerializer):
 """图书数据序列化器"""
 class Meta:
 model = BookInfo
 fields = "__all__"
2) 使用exclude可以明确排除掉哪些字段
class BookInfoSerializer(serializers.ModelSerializer):
 """图书数据序列化器"""
 class Meta:
 model = BookInfo
 exclude = ('id',)
3) 指明只读字段
可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段
class BookInfoSerializer(serializers.ModelSerializer):
 """图书数据序列化器"""
 class Meta:
 model = BookInfo
 fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
 read_only_fields = ('id', 'bread', 'bcomment')
3、添加额外参数
我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数
class BookInfoSerializer(serializers.ModelSerializer):
 """图书数据序列化器"""
 class Meta:
 model = BookInfo
 fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
 extra_kwargs = {
 'bread': {'min_value': 0, 'required': True},
 'bcomment': {'min_value': 0, 'required': True},
 }

2.3 ListSerializer序列化

class BookListSerializers(serializers.ListSerializer):
    """
    # 1. create方法父级ListSerializer已经提供了
      def create(self, validated_data):
      通过self.child来访问绑定的ModelSerializer
        return [
            self.child.create(attrs) for attrs in validated_data
        ]

    """

    # 2、父级ListSerializer没有通过update方法的实现体,需要自己重写
    def update(self, instance, validated_data):
        # ModelSerializer中的update方法
        return [
            # 单个对象     当前要修改的数据
            self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)
        ]

2.4 数据,多表联查

class BookListSerializers(serializers.ListSerializer):
    """
    # 1. create方法父级ListSerializer已经提供了
      def create(self, validated_data):
      通过self.child来访问绑定的ModelSerializer
        return [
            self.child.create(attrs) for attrs in validated_data
        ]

    """

    # 2、父级ListSerializer没有通过update方法的实现体,需要自己重写
    def update(self, instance, validated_data):
        # ModelSerializer中的update方法
        return [
            # 单个对象     当前要修改的数据
            self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)
        ]



class PublishModelSerializer(serializers.ModelSerializer):
    class Meta:
        models = models.Publish
        fields = ["name", "addr"]

class BookSerializers(serializers.ModelSerializer):
    class Meta:
        # 群修改
        list_serializer_class = BookListSerializers
        model = models.Book
        # 1.多表连查

        # fields = ("name", "price", "publish_name", "author_list", 'publish', 'author')
        # 子序列化都是提供给外键(正向方向)完成深度查询的,外键数据是唯一:many=False;不唯一:many=True
        # 注:只能参与序列化,且反序列化不能写(反序列化外键字段会抛异常)
        # # 前提:如果只有查需求的接口,自定义深度还可以用子序列化方式完成
        publish = PublishModelSerializer(many=True)
        fields = ("name", "price", "publish")
        extra_kwargs = {
            "publish": {
                "write_only": True  # 制作反序列化,不做序列化
            },

            "author": {
                "write_only": True
            }

        }

三、单查和群查接口

urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    url(r'^books/$', views.BookAPIView.as_view()),

    url(r'^books/(?P<pk>\d+)/', views.BookAPIView.as_view()),

]

class BookSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        # 1.多表连查
        fields = ("name", "price", "publish_name" ,"author_list")
        # 2.__all__ 获取所有字段
        # fields = "__all__"

        # 3. __exclude__ 除了这个字段
        # exclude = ('id', )
        # 4. depth 深度查询, 与__all__一起连用
        # depth = 2
class BookAPIView(APIView):
    """
        单查:前台数据为pk,接口为 /books/(pk)/
        群查:前台数据为pks,接口为 /books/
    """
    # 单查和群查
    def get(self, request, *args, **kwargs):

        pk = kwargs.get("pk")
        if pk:
            # 单查
            book_obj = models.Book.objects.filter(pk=pk, is_delete=False).first()
            # 判断
            if not book_obj:
                return APIResponse(status=1, msg='get error', http_status=400)
            # 返回数据
            book_data = BookSerializers(book_obj, is_delete=False).data
            return APIResponse(results=book_data)
        else:
            
            # 群查
            book_obj = models.Book.objects.all()
            book_list_data = BookSerializers(book_obj, many=True).data
            return APIResponse(0, "ok", results=book_list_data)

总结:

  1. 单查从请求中获取get单条数据
  2. 过滤False数据库中的记录
  3. 群查序列化,many设置True
  4. 单查群查接口,序列化类提供序列化对象,many参数控制着操作的数据是一条还是多条

四、单删和群删接口

class BookSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        # 1.多表连查
        fields = ("name", "price", "publish_name" ,"author_list")
 def delete(self, request, *args, **kwargs):
        """"
        单删:前台数据为pk,接口为 /books/(pk)/
        群删:前台数据为pks(json),接口为 /books/
        """
        pk = kwargs.get("pk")
         # 将单删群删逻辑整合
        if pk:  # /books/(pk)/的接口就不考虑群删,就固定为单删 请求要带斜杠
            pks = [pk]  # 获取单删
        else:
            # 获取群删
            pks = request.data.get("pk")

        # 判断前台是否是否pk
        if not pks:
            # 前台数据有误,没有提供pk
            return APIResponse(1, "delete error", http_status=400)

        # 返回操作的行,受影响行,就是删除成功,反之失败
        rows = models.Book.objects.filter(is_delete=False, pk__in=pks).update(is_delete=True)
        # 判断是否删除成功
        if rows:
            return APIResponse(0, "delete ok")
        else:
            return APIResponse(0, "delete error")

总结:

  1. delete请求的时候url要添加斜杠,2的后面

  2. 将单删和群删进行逻辑整合

  3. 单删群删接口,后台操作删除字段即可,前台7提供pk就是单删,提供pks就是群删

五、单增和群增接口

class BookSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        # 1.多表连查
        fields = ("name", "price", "publish_name", "author_list", 'publish', 'author')
        extra_kwargs = {
            "publish": {
                "write_only": True  # 制作反序列化,不做序列化
            },
            "author": {
                "write_only": True
            }
        }

class BookAPIView(APIView): 
    def post(self, request, *args, **kwargs):
		
		 """
         save源码
           if self.instance is not None:
            self.instance = self.update(self.instance, validated_data)
            assert self.instance is not None, (
                '`update()` did not return an object instance.'
            )
        else:
            self.instance = self.create(validated_data)
            assert self.instance is not None, (
                '`create()` did not return an object instance.'
            )
		"""
        request_data = request.data
        print(request_data)

        # 单填
        if isinstance(request_data, dict):
            # 校验单条数据
            book_result = BookSerializers(data=request_data)
            # 获取校验结果
            if book_result.is_valid(raise_exception=True):
                book_obj = book_result.save()
                # 返回序列化对象
                return APIResponse(0, "post ok", results=BookSerializers(book_obj).data)
        # 群填
        elif isinstance(request_data, list) and request_data:

            # 校验多条数据
            book_result = BookSerializers(data=request_data, many=True)
            if book_result.is_valid(raise_exception=True):
                # 返回保存对象列表
                book_list_obj = book_result.save()
                # 返回序列化结果
                result = BookSerializers(book_list_obj, many=True)
                return APIResponse(0, 'data ok ', results=result)

        else:
            # 其他错误
            return APIResponse(1, "data error", http_status=400)

总结:

  1. 单条数据为字典,判断是否为字典 ,对数据进行校验,校验结果由is_valid进行处理,保存对象,返回序列化对象
  2. 多条数据,判断是否为列表,列表是否为空,对象进行校验,设置mandy为True校验多条数据,校验结果又is_valid进行处理,保存对象,返回序列化对象结果多条mandy为True
  3. 单增群增接口,根据数据判断是单增还是群增,对应序列化类要设置many,而序列化类只需要通过data即可

六、单条数据整改和多条数据整改

# 序列化.py
class BookListSerializers(serializers.ListSerializer):
    """
    # 1. create方法父级ListSerializer已经提供了
      def create(self, validated_data):
      通过self.child来访问绑定的ModelSerializer
        return [
            self.child.create(attrs) for attrs in validated_data
        ]
    """

    # 2、父级ListSerializer没有通过update方法的实现体,需要自己重写
    def update(self, instance, validated_data):
        # ModelSerializer中的update方法
        return [
            # 单个对象     当前要修改的数据
            self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)
        ]

class BookSerializers(serializers.ModelSerializer):
    class Meta:
        list_serializer_class = BookListSerializers
        model = models.Book
        # 1.多表连查
        fields = ("name", "price", "publish_name", "author_list", 'publish', 'author')
        extra_kwargs = {
            "publish": {
                "write_only": True  # 制作反序列化,不做序列化
            },

            "author": {
                "write_only": True
            }

        }
class BookAPIView(APIView):
    # 单整体改,群整体改
    def put(self, request, *args, **kwargs):
        """
         save源码
           if self.instance is not None:
            self.instance = self.update(self.instance, validated_data)
            assert self.instance is not None, (
                '`update()` did not return an object instance.'
            )
        else:
            self.instance = self.create(validated_data)
            assert self.instance is not None, (
                '`create()` did not return an object instance.'
            )
        单整体改: 前台提交字典,根据pk一个数据,接口/books/(pk)/
        群整体改: 前台提交列表套字典, 接口 /books/ 注每一个字典都可以通过pk添加
        """
        # 单改,将获取的json数据,通过获取pk对应数据库对象记录,进行修改数据
        pk = kwargs.get("pk")
        request_data = request.data

        print(request_data)

        if pk:
            try:
                book_obj = models.Book.objects.get(pk=pk)
            except:
                return APIResponse(1, "pk error")

            # 修改和新增,都需要通过数据,数据依旧给data,修改和新增不同点,需要将被修改对象给instance
            book_ser = BookSerializers(initial=book_obj, data=request_data)
            book_ser.is_valid(raise_exception=True)
            # 在保存数据之前必须调用 is_valid,在保存数据之前不可以调用book_ser不可以调用data属性,以为会提前产生_data

            book_new_obj = book_ser.save()
            return APIResponse(results=BookSerializers(book_new_obj).data)
        else:  # 群改
            if not isinstance(request_data, list) or len(request_data) == 0:
                return APIResponse(1, "data error", http_status=400)

            # [{pk:1,...}, {pk:3,...}, {pk:100,...}] => [obj1, obj3, obj100] + [{...}, {...}, {...}]
            # 要考虑pk对应的对象是否被删,以及pk没有对应的对象
            # 假设pk3被删,pk100没有 => [obj1] + [{...}]

            # 注: 一定不要在循坏体重对循坏对象进行增删(影响对象的长度的操作

            obj_list = []
            data_list = []

            for dic in request_data:
                try:
                    pk = dic.pop("pk")
                    try:
                        obj = models.Book.objects.get(pk=pk, is_delete=False)
                        # 获取对象是否存在
                        obj_list.append(obj)
                        # 添加数据
                        data_list.append(dic)
                    except:
                        pass
                except:
                    return APIResponse(1, "data error", http_status=400)
            #                          修改的对象列表     对应的修改的数据 多条
            book_ser = BookSerializers(instance=obj_list,data=data_list, many=True)
            # 校验数据
            book_ser.is_valid(raise_exception=True)
            book_list_obj = book_ser.save()
            # 返回序列化修改的数据
            return APIResponse(results=BookSerializers(book_list_obj, many=True).data)

总结:

  1. 单整体改和群整体改每个字段必须填,
  2. 没有提供整体改的方法需要自定义类继承ListSerializer类重写update方法,需要在子类进行绑定list_serializer_class = BookListSerializers
  3. 单整体改传参BookSerializers(initial=book_obj, data=request_data)
  4. 群整体改BookSerializers(instance=obj_list,data=data_list, many=True)
  5. 群改,前台提供的数据,后台要转化成要修改的对象们和用来更新的数据们,ModelSerializer设置list_serializer_class关联自己的ListSerializer,重写update方法,完成群改

七、单局部改和群局部改

# 序列化.py
class BookListSerializers(serializers.ListSerializer):
    """
    # 1. create方法父级ListSerializer已经提供了
      def create(self, validated_data):
      通过self.child来访问绑定的ModelSerializer
        return [
            self.child.create(attrs) for attrs in validated_data
        ]
    """

    # 2、父级ListSerializer没有通过update方法的实现体,需要自己重写
    def update(self, instance, validated_data):
        # ModelSerializer中的update方法
        return [
            # 单个对象     当前要修改的数据
            self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)
        ]

class BookSerializers(serializers.ModelSerializer):
    class Meta:
        list_serializer_class = BookListSerializers
        model = models.Book
        # 1.多表连查
        fields = ("name", "price", "publish_name", "author_list", 'publish', 'author')
        extra_kwargs = {
            "publish": {
                "write_only": True  # 制作反序列化,不做序列化
            },

            "author": {
                "write_only": True
            }

        }
class BookAPIView(APIView):
 # 单局部改、群局部改
    def patch(self, request, *args, **kwargs):
        """
         save源码
           if self.instance is not None:
            self.instance = self.update(self.instance, validated_data)
            assert self.instance is not None, (
                '`update()` did not return an object instance.'
            )
        else:
            self.instance = self.create(validated_data)
            assert self.instance is not None, (
                '`create()` did not return an object instance.'
            )
        单局部改: 前台提交字典,根据pk一个数据,接口/books/(pk)/
        群局部改: 前台提交列表套字典, 接口 /books/ 注每一个字典都可以通过pk添加
        """
        # 单改,将获取的json数据,通过获取pk对应数据库对象记录,进行修改数据
        pk = kwargs.get("pk")
        request_data = request.data

        print(request_data)
        print(pk)

        if pk:
            try:
                book_obj = models.Book.objects.get(pk=pk)
            except:
                return APIResponse(1, 'pk error')
            # 局部修改就是在整体修改基础上设置partial=True,将所有参与反序列化字段设置为required=False
            book_ser = BookSerializers(instance=book_obj, data=request_data, partial=True)
            book_ser.is_valid(raise_exception=True)
            book_obj = book_ser.save()
            return APIResponse(results=BookSerializers(book_obj).data)
        else:  # 群改
            if not isinstance(request_data, list) or len(request_data) == 0:
                return APIResponse(1, "data error", http_status=400)

            # [{pk:1,...}, {pk:3,...}, {pk:100,...}] => [obj1, obj3, obj100] + [{...}, {...}, {...}]
            # 要考虑pk对应的对象是否被删,以及pk没有对应的对象
            # 假设pk3被删,pk100没有 => [obj1] + [{...}]

            # 注: 一定不要在循坏体重对循坏对象进行增删(影响对象的长度的操作

            obj_list = []
            data_list = []

            for dic in request_data:
                try:
                    pk = dic.pop("pk")
                    try:
                        obj = models.Book.objects.get(pk=pk, is_delete=False)
                        # 获取对象是否存在
                        obj_list.append(obj)
                        # 添加数据
                        data_list.append(dic)
                    except:
                        pass
                except:
                    return APIResponse(1, "data error", http_status=400)
            #                          修改的对象列表     对应的修改的数据 多条
            book_ser = BookSerializers(instance=obj_list, data=data_list, many=True, partial=True)
            # 校验数据
            book_ser.is_valid(raise_exception=True)
            book_list_obj = book_ser.save()
            # 返回序列化修改的数据
            return APIResponse(results=BookSerializers(book_list_obj, many=True).data)

总结:

  1. 单局部改和群局部改每个字段必须填,
  2. 没有提供整体改的方法需要自定义类继承ListSerializer类重写update方法,需要在子类进行绑定list_serializer_class = BookListSerializers
  3. 单局部改传参BookSerializers(initial=book_obj, data=request_data,partial=True)
  4. 单局部改BookSerializers(instance=obj_list,data=data_list, many=True,partial=True)
  5. 单局部改,序列化类参数instance=修改的对象, data=修改的数据, partial=是否能局部修改,单整体修改就是partial=False(默认就是False)

八、子序列化

class PublishModelSerializer(serializers.ModelSerializer):
    class Meta:
        models = models.Publish
        fields = ["name", "addr"]

class BookSerializers(serializers.ModelSerializer):
    class Meta:
        list_serializer_class = BookListSerializers
        model = models.Book
        # 1.多表连查

        # fields = ("name", "price", "publish_name", "author_list", 'publish', 'author')
        # 子序列化都是提供给外键(正向方向)完成深度查询的,外键数据是唯一:many=False;不唯一:many=True
        # 注:只能参与序列化,且反序列化不能写(反序列化外键字段会抛异常)
        # # 前提:如果只有查需求的接口,自定义深度还可以用子序列化方式完成
        publish = PublishModelSerializer(many=True)
        fields = ("name", "price", "publish")
class BookAPIView(APIView):
    """
        单查:前台数据为pk,接口为 /books/(pk)/
        群查:前台数据为pks,接口为 /books/
        过滤删除的字段
    """

    # # 单查和群查
    def get(self, request, *args, **kwargs):

        pk = kwargs.get("pk")
        if pk:
            # 单查
            book_obj = models.Book.objects.filter(pk=pk, is_delete=False).first()
            # 判断
            if not book_obj:
                return APIResponse(status=1, msg='get error', http_status=400)
            # 返回数据
            book_data = BookSerializers(book_obj).data
            return APIResponse(results=book_data)
        else:
            # 群查
            book_obj = models.Book.objects.filter(is_delete=False).all()
            book_list_data = BookSerializers(book_obj, many=True).data
            return APIResponse(0, "ok", results=book_list_data)

总结:

  1. 子序列化都是提供给外键(正向方向)完成深度查询的,外键数据是唯一:many=False;不唯一:many=True
  2. 只能参与序列化,且反序列化不能写(反序列化外键字段会抛异常)
  3. 如果只有查需求的接口,自定义深度还可以用子序列化方式完成

总结

  1. get: 单查,群查
  2. post: 单增,群增
  3. delete: 单删,群山(都是自己实现)
  4. put:单整体改,群整体改
  5. patch: 单局部改,群局部改
posted @ 2020-02-10 20:01  RandySun  阅读(282)  评论(0编辑  收藏  举报