• 基类,子序列化、多表序列化与反序列化


    基表

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

    序列化类其他配置(了解)

    class AuthorModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Author
            # 不常用,将全部字段提供给外界
            fields = '__all__' 
            
    # ------------------------------------------------------------------
    
    class AuthorModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Author
            # 不常用,排除指定字段的其他所有字段,不能自动包含 外键反向 字段
            exclude = ['is_delete', 'updated_time']  
            
    # ------------------------------------------------------------------
    
    class AuthorModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Author
            # 'detail', 'books' 是 外键(正向|反向) 字段
            fields = ['name', 'detail', 'books']
            # 不常用,自动深度,自动深度会显示外键关联表的所有字段
            depth = 2  
    # 正向外键字段:就是外键的属性名
    # 反向外键字段:就是外键属性设置的related_name

    子序列化

    1)子序列化的字段,必须是 外键(正向|反向) 字段

    2)子序列化对应的数据是单个many=False,数据对应是多个many=True

    3)子序列化其实就是自定义序列化字段,覆盖了原有 外键(正向|反向)字段 的规则,所以不能进行反序列化

    案例

    urls.py

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

    serializers.py

    from rest_framework import serializers
    from . import models
    class AuthorDetailModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.AuthorDetail
            fields = ['phone']
    
    class BookModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = ['name', 'price']
    
    class AuthorModelSerializer(serializers.ModelSerializer):
        # 子序列化:子序列化类必须写在上方,且只能对 外键(正向反向)字段 进行覆盖
        # 注:运用了子序列化的外键字段,就不能进行数据库的反序列化过程
        detail = AuthorDetailModelSerializer(many=False, read_only=True)
        books = BookModelSerializer(many=True, read_only=True)
        # 问题:
        # 1)不设置read_only时,就相当于允许反序列化,反序列化是就会报错
        # 2)设置read_only时,可以完成反序列化,但是新增的数据再序列化了,就没有外键关联的数据,与原来数据格式就不一致了
        class Meta:
            model = models.Author
            fields = ['name', 'detail', 'books']

    views.py

    # 实际开发,资源的大量操作都是查询操作,只有查需求的资源,可以采用子序列化
    class AuthorAPIView(APIView):
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if pk:
                obj = models.Author.objects.filter(is_delete=False, pk=pk).first()
                serializer = serializers.AuthorModelSerializer(instance=obj)
                return APIResponse(result=serializer.data)
            else:
                queryset = models.Author.objects.filter(is_delete=False).all()
                serializer = serializers.AuthorModelSerializer(instance=queryset, many=True)
                return APIResponse(results=serializer.data)
    
        # 测试子序列化外键字段,不能参与反序列化,因为
        def post(self, request, *args, **kwargs):
            serializer = serializers.AuthorModelSerializer(data=request.data)
            if serializer.is_valid():
                obj = serializer.save()
                return APIResponse(result=serializers.AuthorModelSerializer(instance=obj).data, http_status=201)
            else:
                # 校验失败 => 异常响应
                return APIResponse(1, serializer.errors, http_status=400)

    多表序列化与反序列化

    1)外键字段要参与反序列化,所以外键字段设置为write_only

    2)外键关系需要连表序列化结果给前台,可以用@property来自定义连表序列化

    案例

    urls.py

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

    models.py

    class Book(BaseModel):
        # ...
        
        @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
    
        @property  # 借助序列化类完成序列化过程
        def read_author_list(self):
            from .serializers import AuthorModelSerializer
            return AuthorModelSerializer(self.authors.all(), many=True).data

    serializers.py

    # 辅助序列化类
    class AuthorDetailModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.AuthorDetail
            fields = ['phone']
    
    # 辅助序列化类
    class AuthorModelSerializer(serializers.ModelSerializer):
        detail = AuthorDetailModelSerializer(many=False, read_only=True)
        class Meta:
            model = models.Author
            fields = ['name', 'detail']
    
    
    # 主序列化类
    class BookModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = ('name', 'price', 'image', 'publish', 'authors', 'publish_name', 'author_list', 'read_author_list')
            extra_kwargs = {
                'image': {
                    'read_only': True,
                },
                'publish': {  # 系统原有的外键字段,要留给反序列化过程使用,序列化外键内容,用@property自定义
                    'write_only': True,
                },
                'authors': {
                    'write_only': True,
                }
            }

    views.py

    # 六个必备接口:单查、群查、单增、单删、单整体改(了解)、单局部改
    # 四个额外接口:群增、群删、群整体改、群局部改
    class BookAPIView(APIView):
        # 单查群查
        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)
    
    
        # 单增群增
        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)  # 如果校验失败,会直接抛异常,返回给前台,只要其中一个字典出错就不会走save方法
                objs = serializer.save()
                # 为什么要将新增的对象重新序列化给前台:序列化与反序列化数据不对等
                return APIResponse(result=serializers.BookModelSerializer(objs, many=True).data, http_status=201)
    
    # 友情注释:群增其实是借助了ListSerializer来的create方法完成的
  • 相关阅读:
    客户端及服务端_终端模拟
    安装-homebrew
    客户端及服务端_网页访问
    python server搭建
    ping不通localhost但是可以ping通ip地址
    CentOS7 修改Jenkins以root用户运行
    tomcat配置外部静态资源映射路径(windows和Linux部署)
    Centos 6.10 安装 Jenkins
    axios ios 微信浏览器session问题
    微信公众号 分享接口 签名通过 分享无效果(JSSDK自定义分享接口的策略调整)
  • 原文地址:https://www.cnblogs.com/baohanblog/p/12337412.html
Copyright © 2020-2023  润新知