序列化

序列化

1、二次封装Response

我们在views.py中不管是增删改查操作后都要通过Response返回status,msg或者网络状态码与状态信息和外界传来的数据,因此我们可以将这些全部封装到一个类中

新建response.py文件

from rest_framework.response import Response
​
# 自定义response类
class APIResponse(Response):
    def __int__(self, status=0, msg='ok', http_status=None, headers=None,
                 exception=False, **kwargs):
        # 将外界传来的数据存储在kwargs中,外界传来的数据状态码,状态信息及其他额外字段都格式化成data数据
        data= {
            'status': status,
            'msg': msg
        }
        if kwargs:
            data.update(kwargs)
        # 继承原有的网络状态码及状态信息
        super().__init__(data=data, status=http_status, headers=headers, exception=exception)

使用:在views中直接使用默认就是{"status": 0, "msg": "ok"}

# APIResponse() 代表就返回 {"status": 0, "msg": "ok"}
# APIResponse(result="结果") 代表返回 {"status": 0, "msg": "ok", "result": "结果"}
# APIResponse(status=1, msg='error', http_status=400, exception=True) 异常返回 {"status": 1, "msg": "error"}

2、数据库关系分析

1、两张表之间有关系的,进行增删改的操作的时候都会相互影响(效率低),查询操作正常

2、有关系的两张表,断开关联,但原来的数据保持与原来一致,每张表都可以单独操作,增删改操作效率极高,但是容易出现脏数据(开发中可以避免),由于数据没有任何变化,查询操作不会受影响

3、Django的ORM支持断关联操作关系表,且所有的操作方式与没有断开关联操作一致

3、ORM操作关系

1、外键位置

1、一对多:外键字段ForeignKey必须在多的一方,书与出版社,外键在书表中

2、多对多:ManyToManyField放在任何一方都可以,因为会创建第三张关系表,用两个外键分别关联两个表

3、一对一:OneToOneField放在依赖的表,作者与作者详情,放在详情表中,OneToOneField也可以转换成 外键 + 唯一约束

2、ORM关系Field

1、ForeignKey可以设置related_name,db_constraint,on_delete

2、OneToOneField可以设置related_name,db_constraint,on_delete

3、ManyToManyField可以设置related_name,db_constraint

不能设置on_delete,原因:不管是关联在哪张表上,数据修改,都会影响到关系表(默认级联),如果想控制,只能自定义关系表,在关系表的两个外键分别设置on_delete

3、related_name,db_constraint,on_delete参数含义

1、related_name:表之间反向访问的名字,默认是表名小写 | 表名小写_set,正向外键字段就是属性名,反向外键字段就是设置的related_name

2、db_constraint:表之间的关联关系,默认是True,代表关联,手动设置为False断关联,提高增删改操作,且其他操作不会受影响

3、on_delete:在Django 1.x默认就是CASCADE级联删除,在Django2.x下必须手动明确

4、表关系:级联、不做任何事、设置默认值、设置空

1、作者没,作者详情一定没用:CASCADE

2、作者没,书还在:DO_NOTHING

3、部门没,员工进入未分组部门:SET_DEFAULT (需要配合default属性使用)

4、部门没,员工部门的外键字段设为空,SET_NULL (需要配合null=True属性使用)

class Author(models.Model):
    name = models.CharField(max_length=64)
​
​
class AuthorDetail(models.Model):
    phone = models.CharField(max_length=11)
    # 外键字段设置依赖的一方
    author = models.OneToOneField(
        to=Author,
        related_name='detail',  # 反向访问的名字
        db_constraint=False,  # 表之间的关联,断关联
        on_delete=models.SET_NULL,  # 关联的外键没,设为空
        null=True
    )

测试:

import os, django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "d_proj.settings")
django.setup()
​
from api.models import Author, AuthorDetail
​
# 测试正向反向查询
# a1 = Author.objects.first()
# print(a1.name)
# print(a1.detail.phone)
# ad2 = AuthorDetail.objects.last()
# print(ad2.phone)
# print(ad2.author.name)
# 级联关系测试
# ad2 = AuthorDetail.objects.last()  # type: AuthorDetail
# ad2.delete()
# Author.objects.first().delete()

4、基表

抽象出各表中共有的字段,并且不会完成数据库迁移,必须配置abstract=True,其他表继承该表即可

# 基类:是抽象的(不会完成数据库迁移),目的是提供共有字段的
class BaseModel(models.Model):
    is_delete = models.BooleanField(default=False)
    updated_time = models.DateTimeField(auto_now_add=True)
​
    class Meta:
        abstract = True  # 必须完成该配置

5、序列化类其他设置

1、fields='__ all__' 将全部字段提供给外界(不常用)

class AuthorModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Author
        # 不常用,将全部字段提供给外界
        fields = '__all__' 

2、exclude=['is_delete', 'updated_time'] 排除指定字段,返回其他字段,但是不能包含外键的反向字段(不常用)

class AuthorModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Author
        # 不常用,排除指定字段的其他所有字段,不能自动包含 外键反向 字段
        exclude = ['is_delete', 'updated_time']  

3、depth自动深度,自动深度会显示外键关联的所有字段(不常用)

class AuthorModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Author
        # 'detail', 'books' 是 外键(正向|反向) 字段
        fields = ['name', 'detail', 'books']
        # 不常用,自动深度,自动深度会显示外键关联表的所有字段
        depth = 2  

4、子序列化:对于只有查操作的时候我们可以采用子序列化

  1. 子序列化的字段,必须是外键字段,不管是正向反向,并且多表才有子序列化

  2. 子序列化的类必须写在上面,并且序列化的数据是单个默认是many=False,多个数据对应时many=True

  3. 子序列化其实就是自定义序列化字段,覆盖了原有的外键字段的规则,所有不能进行反序列化,只能读不能写入,所以只能针对只有查操作的时候采用

class AuthorDetailSerializer(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):
    # 子序列化类必须写在上方,并且只能对外键字段覆盖,不能进行写操作反序列化,所以只能对于只查的操作
    # 不设置read_only,相当于允许反序列化,而本身就不能反序列化,反序列化会报错
    # 设置了read_only,反序列化不会报错,但是新增的数据没有外键字段的数据
    # books = BookModelSerializer(many=True)
    books = BookModelSerializer(many=True, read_only=True)
    # detail = AuthorDetailSerializer()
    detail = AuthorDetailSerializer(read_only=True)
    class Meta:
        model = models.Author
        fields = ['name', 'books', 'detail']

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

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

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

3、字段少时可以自定义序列化逻辑,字段多时可以借助序列化类子序列化来完成序列化过程

models.py

class Book(BaseModel):
    # ...
    
    @property  # @property字段默认就是read_only,且不允许修改
    def publish_name(self):
        return self.publish.name

    @property  # 1字段少可以用自定义序列化过程
    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  # 2字段多可以用借助序列化类完成序列化过程
    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,
            }
        }

7、单增和群增

1、如何区别是单增还是群增:判断request.data是{ }单增还是[ ]群增

2、群增如果有一个失败会直接抛出异常给前台,其他数据也不会存入数据库中

    # 单增群增
    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)

 

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