zoukankan      html  css  js  c++  java
  • 十大接口序列化 过渡写法

    序列化类外键字段的覆盖

    1. 在序列化类中自定义字段,名字与model类中属性名一致,就称之为覆盖操作

      (覆盖的是属性的所有规则:extra_kwargs中指定的简易规则、model字段提供的默认规则、数据库唯一约束等哪些规则)

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

      只读:read_only=True

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

      可读可写: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')
    


    十大接口序列化

    """
    def __init__(self, instance=None, data=empty, **kwargs):
        pass
    
    instance:是要被赋值对象的 - 对象类型数据赋值给instance
    data:是要被赋值数据的 - 请求来的数据赋值给data
    kwargs:内部有三个属性:many、partial、context
        many:操作的对象或数据,是单个的还是多个的
        partial:在修改需求时使用,可以将所有校验字段required校验规则设置为False
        context:用于视图类和序列化类直接传参使用
    """
    
    # 常见使用
    # 单查接口
    UserModelSerializer(instance=user_obj)
    
    # 群查接口
    UserModelSerializer(instance=user_query, many=True)
    
    # 单增接口,request.data是字典
    UserModelSerializer(data=request.data) 
    
    # 群增接口,request.data是列表
    UserModelSerializer(data=request.data, many=True)
    
    # 单整体改接口,request.data是字典
    UserModelSerializer(instance=user_obj, data=request.data)
    
    # 群整体改接口,request.data是列表,且可以分离出pks,转换成user_queryset
    UserModelSerializer(instance=user_queryset, data=request.data, many=True)
    
    # 单局部改接口,request.data是字典
    UserModelSerializer(instance=user_obj, data=request.data, partial=True)
    
    # 群局部改接口,request.data是列表,且可以分离出pks,转换成user_queryset
    UserModelSerializer(instance=user_queryset, data=request.data, partial=True, many=True)
    
    # 单删群删接口,用不到序列化类
    

    十大接口核心知识总结

    1. 初始化序列化类,设置partial=True可以将所有反序列化字段的 required 设置为 False(提供就校验,不提供不校验),可以运用在局部修改接口
    2. 初始化序列化类,设置context={...},在序列化类操作self.context,实现视图类和序列化类数据互通
    3. 只有要完成资源的群改这种特殊需求时,才需要自定义ListSerializer绑定给自定义的ModelSerializer,重写update方法,来完成需求

    案例

    models.py

    # 基类:是抽象的(不会完成数据库迁移),目的是提供共有字段的
    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)
    

    urls.py

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

    serizlizers.py

    from rest_framework import serializers
    from . import models
    
    # 群增群改辅助类(了解)
    class BookListSerializer(serializers.ListSerializer):
        """
        1)create群增方法不需要重新
        2)update群改方法需要重写,且需要和views中处理request.data的逻辑配套使用
        3)self.child就代表该ListSerializer类绑定的ModelSerializer类
            BookListSerializer的self.child就是BookModelSerializer
        """
        # 重新update方法
        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')
            # fields = ('name', 'price', 'image', 'publish', 'authors', 'abc')
            extra_kwargs = {
                'image': {
                    'read_only': True,
                },
                'publish': {  # 系统原有的外键字段,要留给反序列化过程使用,序列化外键内容,用@property自定义
                    'write_only': True,
                },
                'authors': {
                    'write_only': True,
                },
            }
    
        # 需求:内外传参
        # 1)在钩子函数中,获得请求请求对象request 视图类 => 序列化类
        # 2)序列化钩子校验过程中,也会产生一些数据,这些数据能不能传递给外界使用:序列化类 => 视图类
        # 序列化类的context属性,被视图类与序列化类共享
        def validate(self, attrs):
            print(self.context)  # 可以获得视图类在初始化序列化对象时传入的context
            # self.context.update({'a': 10})  # 序列化类内部更新context,传递给视图类
            return attrs
    
    

    views.py

    from rest_framework.views import APIView
    from . import models, serializers
    from .response import APIResponse
    
    # 六个必备接口:单查、群查、单增、单删、单整体改(了解)、单局部改
    # 四个额外接口:群增、群删、群整体改、群局部改
    class BookAPIView(APIView):
        # 单查群查
        """
        单查:接口:/books/(pk)/
        群查:接口:/books/
        """
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if pk:
                obj = models.Book.objects.filter(is_delete=False, pk=pk).first()
                serializer = serializers.BookModelSerializer(instance=obj)
                return APIResponse(result=serializer.data)
            else:
                queryset = models.Book.objects.filter(is_delete=False).all()
                serializer = serializers.BookModelSerializer(instance=queryset, many=True)
                return APIResponse(results=serializer.data)
    
        # 单增群增
        """
        单增:接口:/books/   数据:dict
        群增:接口:/books/   数据:list
        """
        def post(self, request, *args, **kwargs):
            # 如何区别单增群增:request.data是{}还是[]
            if not isinstance(request.data, list):
                # 单增
                serializer = serializers.BookModelSerializer(data=request.data)
                serializer.is_valid(raise_exception=True)  # 如果校验失败,会直接抛异常,返回给前台
                obj = serializer.save()
                # 为什么要将新增的对象重新序列化给前台:序列化与反序列化数据不对等
                return APIResponse(result=serializers.BookModelSerializer(obj).data, http_status=201)
            else:
                # 群增
                serializer = serializers.BookModelSerializer(data=request.data, many=True)
                serializer.is_valid(raise_exception=True)  # 如果校验失败,会直接抛异常,返回给前台
                objs = serializer.save()
                # 为什么要将新增的对象重新序列化给前台:序列化与反序列化数据不对等
                return APIResponse(result=serializers.BookModelSerializer(objs, many=True).data, http_status=201)
    
        # 单删群删
        """
        单删:接口:/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 APIResponse(1, '数据有误')
    
            if rows:  # 只要有受影响的行,就代表删除成功
                return APIResponse(0, '删除成功')
    
            return APIResponse(2, '删除失败')
    
        # 单整体改群整体改
        """
        单整体改:接口:/books/(pk)/ 数据:dict
        群整体改:接口:/books/   数据:[{pk1, ...}, ..., {pkn, ...}] | {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)
    
    
        # 单局部改群局部改
        """
        单局部改:接口:/books/(pk)/ 数据:dict
        群局部改:接口:/books/   数据:[{pk1, ...}, ..., {pkn, ...}] | {pks: [pk1, ..., pkn], data: [{}, ..., {}]}
        """
        def patch(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)
                # partial=True就是将所有反序列化字段的 required 设置为 False(提供就校验,不提供不校验)
                serializer = serializers.BookModelSerializer(instance=instance, data=request.data, partial=True)
                serializer.is_valid(raise_exception=True)
                obj = serializer.save()
                return APIResponse(result=serializers.BookModelSerializer(obj).data)
            else:  # 群
                pks = []
                try:  # 只要不是要求的标准数据,一定会在下方三行代码某一行抛出异常
                    for dic in request.data:
                        pks.append(dic.get('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,
                    partial=True,
                    context={'request': request}  # 初始化时,对context赋值,将视图类中数据传递给序列化类
                )
    
                serializer.is_valid(raise_exception=True)
                objs = serializer.save()
    
                print(serializer.context)  # 在完成序列化类校验后,可以重新拿到序列化类内部对context做的值更新
                return APIResponse(result=serializers.BookModelSerializer(objs, many=True).data)
    
  • 相关阅读:
    Elementary Methods in Number Theory Exercise 1.3.13
    Elementary Methods in Number Theory Exercise 1.3.17, 1.3.18, 1.3.19, 1.3.20, 1.3.21
    数论概论(Joseph H.Silverman) 习题 5.3,Elementary methods in number theory exercise 1.3.23
    Elementary Methods in Number Theory Exercise 1.2.31
    数论概论(Joseph H.Silverman) 习题 5.3,Elementary methods in number theory exercise 1.3.23
    Elementary Methods in Number Theory Exercise 1.3.13
    Elementary Methods in Number Theory Exercise 1.3.17, 1.3.18, 1.3.19, 1.3.20, 1.3.21
    Elementary Methods in Number Theory Exercise 1.2.31
    Elementary Methods in Number Theory Exercise 1.2.26 The Heisenberg group
    4__面向对象的PHP之作用域
  • 原文地址:https://www.cnblogs.com/kai-/p/12342875.html
Copyright © 2011-2022 走看看