• DRF之子序列化、model类(四)


    一、二次封装Resonse

    responses.py
    from rest_framework.response import Response
    class APIResponse(Response):
        def __init__(self, status=None, msg=None, http_status=None, *args, **kwargs):
            data = {
                'status': status,
                'msg': msg,
            }
            if kwargs:
                data.update(kwargs)
            super().__init__(status=http_status,data=data)
    
    

    二、数据库关系分析

    '''
    1.相互有关系的两张表,增删改操作会相互影响,导致效率低下,查询操作就是正常的连表操作
    
    2.相互有关的两张表,断开外键关系,但从代码逻辑层面保持原来的联系
    	- 这样一来,每个表都可以单独操作,提高了增删改查的效率,在开发中要避免由此带来的脏数据,事务 + 代码层面的逻辑约束
    	- 由于数据没有发生变化,查询的连表操作不会受到影响
    
    3. django的orm支持断关联操作关系表,且所有的操作方式和没有断开关联的操作是一致的(在django2.0以上默认不进行级联更新)
    
    '''
    

    三、orm操作关系

    '''
    外键位置:
    1.一对多的外键关系,FK毫无疑问建立在多的乙方,如书与出版社,外键应该放在书表中。
    2.多对多的外键关系,ManyToManyField放在任一一端都可以,因为会创建第三章关系表,在关系表中用两个外键分别关联两个表
    
    3.一多一的的外键关系,OneToOneField放在依赖的表,如作者与作者详情表,作者详情依赖于作者,所以将其放在作者详情表。
    OneToOneField会被转换为外键+ 位移约束。
    
    '''
    
    '''
    ORM关系Field:
    ForeignKey可以设置related_name, db_constraint, on_delete
    OneToOneField可以设置related_name, db_constraint, on_delete
    ManyToManyField只能设置related_name, db_constraint
    	- 不能设置on_delete的原因:无论放在A表还是B表,第三张表都会受到影响。
    	- 可以自定义关系表,在关系表的两个外键分别设置on_delete
    '''
    
    '''
    各参数的含义:
    related_name:表之间反向访问的名字,默认是表名小写|表名小写_set
    db_constraint:表之间的关联关系,默认为True为关联。设置为False,可以提高增删改查的效率,且不影响其他操作
    on_delete:在django 1.x下默认是CASCADE,在django 2.x中需要手动。
    '''
    
    '''
    表关系:
    作者详情依赖于作者,作者被删除跟着被删除:CASCADE
    作者与书的关系,当作者被删除,书不变:DO_NOTHING
    
    部门表与员工表,一条部门记录被删除时,
    部门内的员工全部进入未分组部门:SET_DEFAULT(需要配合default属性使用)
    或
    部门内的员工外键字段设置为空:SET_NULL(需要配合null=True属性使用)
    '''
    
    案例测试
    import os, django
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day69.settings")
    django.setup()
    
    from api.models import Author, AuthorDetail
    
    # print(Author.objects.all())
    # print(AuthorDetail.objects.all())
    #
    # AuthorDetail.objects.first().delete() # type Author
    #
    # print(Author.objects.all())
    # print(AuthorDetail.objects.all())
    
    obj = Author.objects.first()
    print(obj.name,obj.detail.phone)
    
    d_obj = AuthorDetail.objects.first()
    print(d_obj.phone,d_obj.author.name)
    

    四、基表

    # 基类:是抽象的(不会完成数据库迁移),目的是提供共有字段的
    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.子序列化其实就是自定义序列化字段,覆盖了原有外键字段的规则,所以不能进行反序列化********
    
    '''
    
    案例

    serializers.py

    from rest_framework import serializers
    from . import models
    
    class AuthorDetailModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.AuthorDetail
            fields = ['phone']
    
    # 子序列化detail字段
    class AuthorModelSerializer(serializers.ModelSerializer):
        detail = AuthorDetailModelSerializer(many=False)
        class Meta:
            model = models.Author
            fields = ['name','detail']
            
    # 子序列化author字段
    class BookModelSerializer(serializers.ModelSerializer):
        author = AuthorModelSerializer(many=True)
        class Meta:
            model = models.Book
            # fields = ['name', 'price']
            # fields = '__all__'
            # exclude = ['is_delete','create_time']
            # depth = 1
            fields = ['name', 'price', 'author']
    

    七、多表序列化与反序列化

    '''
    1.外键字段要参与反序列化,所以外键字段设置为write_only
    2.外键关系需要联表序列化结果(而不是仅返回外键字段的id),可以在model中自定义@property来自定义联表序列化
    '''
    
    

    完成反序列化仅仅需要将外键字段在fields中声明即可

    class BookModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            # author和publish都为外键字段
            fields = ['name', 'price', 'author','publish']
    
    # 请求数据格式----drf能自动识别需要接受的类型如[]
    {
    	"name":"西游记1",
    	"price":"6.66",
    	"author":[2,3],
    	"publish":1
    }
    

    序列化数据:由于将外键字段留给了反序列化使用,需要在model类中定义@property属性(默认只参与序列化)同时设置原来的外键字段write_only

    serializers.py
    class BookModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            # author和publish都为外键字段
    		fields = ['name', 'price', 'author','publish','publish_name','author_list']     
            extra_kwargs = {
                'author':{
                    'write_only':True
                },
                'publish': {
                    'write_only': True
                }
            }
    
    models.py
    class Book(BaseModel):
        name = models.CharField(max_length=64)
        price = models.DecimalField(max_digits=8, decimal_places=2)
    
        publish = models.ForeignKey(to='Publish', related_name='books', db_constraint=False, on_delete=models.DO_NOTHING)
        author = models.ManyToManyField(to='Author', related_name='books', db_constraint=False)
    
        @property
        def publish_name(self):
            return self.publish.name
    
    '''方式一
        @property
        def read_author_list(self):
            a_list = []
            for author_obj in self.author.all():
                info_dict = {}
                info_dict['name'] = author_obj.name
                # detail字段可能为空
                try:
                    info_dict['phone'] = author_obj.detail.phone
                except:
                    info_dict['phone'] = ''
                a_list.append(info_dict)
            return a_list
    '''
    
    # 方式二:需要辅助类
        @property
        def author_list(self):
            from .serializers import AuthorModelSerializer
            return AuthorModelSerializer(self.author.all(),many=True).data
    
    
    
    views.py
    from rest_framework.views import APIView
    from . import models
    from . import serializers
    from .responses import APIResponse
    from rest_framework import status
    
    # 六个必备接口:单查(✔)、群查(✔)、单增(✔)、单删、单整体改(了解)、单局部改
    # 四个额外接口:群增(✔)、群删、群整体改、群局部改
    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()
                if obj:
                    serializer = serializers.BookModelSerializer(obj, many=False)
                    return APIResponse(status=0, msg='ok', result=serializer.data, http_status=200)
                else:
                    return APIResponse(status=0, msg='data not exists')
            else:
                objs = models.Book.objects.all()
                serializer = serializers.BookModelSerializer(objs, many=True)
                return APIResponse(status=0, msg='ok', result=serializer.data, http_status=200)
    
        def post(self, request, *args, **kwargs):
            data = request.data
            # 是否多个数据进行判断
            # 单增
            if not isinstance(data, list):
                serializer = serializers.BookModelSerializer(data=data)
                serializer.is_valid(raise_exception=True)
                obj = serializer.save()
                return APIResponse(status=0, msg='ok', result=serializers.BookModelSerializer(obj, many=False).data,
                                   http_status=201)
            # 群增
            else:
                serializer = serializers.BookModelSerializer(data=data,many=True)
                serializer.is_valid(raise_exception=True)
                objs = serializer.save()
           	# 将objs重新序列化返回给前端(序列化与反序列化信息不对等)
                return APIResponse(status=0,msg='ok',result=serializers.BookModelSerializer(objs,many=True).data,http_status=status.HTTP_201_CREATED)
    
            
    # 友情注释:群增其实是借助了ListSerializer来的create方法完成的
    

    小结

    """
    1)二次封装Response:
    	自定义类继承Response,重写init方法,在内部格式化data
    	
    2)表关系分析:
    	断关联:
    		优点:提示增删改操作效率,不允许查效率
    		缺点:增删改操作可能会导致脏数据,所以需要通过逻辑或是事务来保证
    		
    3)ORM表关系处理语法:
    	1)外键所在位置
    	2)如何断关联db_constraint
    	3)正向方向自定义名字:related_name
    	4)表关系:on_delete四种
    	
    4)基表:Meta中配置abstract=True,来被继承,提供共有字段
    
    5)多表连表Meta中的了解配置
    	fields = '__all__'  # 不常用,将全部字段提供给外键
        exclude = ['is_delete', 'updated_time']  # 不常用,排除指定字段的其他所有字段
        depth = 2  # 不常用,主动深度,自动深度会显示关联表的所有字段
        
    6)子序列化
    	i)通常只用于序列化过程,对外键字段进行了覆盖,影响外键字段的反序列化过程
    	class SubSerializer:
    		pass
    	class SupSerializer:
    		外键 = SubSerializer(many=True|False)
    	
    7)多表的序列化与反序列化
    	1)连表序列化用自定义@property完成:内部实现可以自定义逻辑,也可以走序列化类
    	2)外键字段留给反序列化来使用
    	
    8)单查、群查、单增、群增接口
    """
    
  • 相关阅读:
    Prism之12345
    Struts2注解学习1
    模拟Spring依赖注入
    Spring的IOC注解学习
    Hibernate注解学习1
    Redis源码分析(二十六) slowLog和hyperloglog
    做优秀产品经理所需的7种素质
    程序员学习英语
    PL/SQL Developer记住密码设置
    oracle11g,安装及net Manager的配置
  • 原文地址:https://www.cnblogs.com/Ghostant/p/12348054.html
Copyright © 2020-2023  润新知