drf序列化与反序列化,基表的概念

在序列化与反序列化之前,需要了解的知识点

模型表知识点

基表的概念:

  创建的基表其他表可以继承,能继承其中的字段,用于许多张表共有几个字段时,可以使用基表

基表创建方式:

class BaseModel(models.Model):
    create_time = models.DateTimeField(auto_now_add=True)
    is_delete = models.BooleanField(default=False)

    class Meta:
        # abstract默认为False
        # abstract为True不会创建此表
        abstract = True

外键字段中的断连接,反向查询与on_delete

class AuthorDetail(BaseModel):
    adders = models.CharField(max_length=255)
    mobile = models.CharField(max_length=11)
    author = models.OneToOneField(
        to='Author',
        # 反向查询都是通过related_name,默认情况都是表名小写
        # 用原生orm时,反向查询结果为多个时,需要加_set,但是一旦定义related_name,反向查询结果为多个时,也不需要加_set
        related_name='detail',
        # 断关联
        # 减缓数据库压力
        db_constraint=False,
        # on_delete 默认情况下是models.CASCADE
        # DO_NOTHING author记录删除,详情表不做任何修改
        # SET_DEFAULT 作者记录被删除时,author一对一字段会变成你设置的默认值,不过你要提前设置default
        # SET_NULL 作者记录被删除时,author一对一字段会变成空(null) 也要提前设置null=True
        on_delete=models.DO_NOTHING
    )

    class Meta:
        db_table = 'day71_author_detail'
        verbose_name = '作者详情'
        verbose_name_plural = verbose_name

    def __str__(self):
        return '%s的详情' % self.author.name

注:

  断连情况下,两张表已经没有数据库关系了,再去操作数据库不会级联更新级联删除

  我们加的on_delete=models.CASCADE是让orm通过逻辑进行级联删除

序列化与反序列化(ModelSerializer)

序列化

class Publishserializers(serializers.ModelSerializer):
    class Meta:
        model = models.Publish
        fields = ('name', 'adders')


class Bookserializers(serializers.ModelSerializer):
    # 自定义字段必须写在fields中
    # 了解: 该方式设置的序列化字段,必须在fields中声明
    # 自定义连表深度 - 子序列化方式
    # 如果自定义字段与model类中的字段重名时,会走自定义字段
    publish = Publishserializers()
    class Meta:
        model = models.Book
        fields = ('name', 'price', 'publish', 'get_author', 'gender')

        # 所有字段
        # fields = '__all__'
        # 与fields不共存,exclude排除哪些字段
        # exclude = ('id', 'is_delete', 'create_time')
        # 自动连表深度
        # depth = 1

序列化fields中可以添加模型类中序列化插拔属性,

说的简单点就是,在模型类中定义方法,最好是用property装饰器装饰

# 序列化插拔式属性 - 完成自定义字段名完成连表查询
    @property
    def get_author(self):
        # print(self.authors, type(self.authors))
        return self.authors.values('name', 'age')

模型类中的插拔式属性,在序列化中的fields可写可不写

注:

  自定义字段最好不要与模型表中的字段重名

反序列化

class BookDeserializers(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = ('name', 'price', 'publish', 'authors')
        # extra_kwargs为了反序列化时添加系统校验
        extra_kwargs = {
            'name': {
                'max_length': 10,
                'min_length': 3,
                # required默认为True,所以默认为必填字段
                'required': True,
                'error_messages': {
                    'max_length': '姓名最长10位',
                    'min_length': '姓名最短3位',
                    'required': '姓名必填'
                }
            },
        }
    
    # 局部钩子
    def validate_name(self, value):
        if 'g' in value:
            raise exceptions.ValidationError('你这个鸡贼')
        return value

    # 全局钩子
    def validate(self, attrs):
        # 外键字段前端传过来的都是id值,但是后端会将其转成对象,
        # 如果传过来的id值,并不在数据库中,会直接报错,如果我们写了raise_exception=True会直接将错返回给前端
        book_obj = models.Book.objects.filter(publish=attrs.get('publish'), name=attrs.get('name'))
        # print(book_obj)
        if book_obj:
            raise exceptions.ValidationError({"name": '书名重复'})
        return attrs

序列化与反序列化可以合并,上面只是方便演示

"""
1) fields中设置所有序列化与反序列化字段
2) extra_kwargs划分只序列化或只反序列化字段
    write_only:只反序列化
    read_only:只序列化
    自定义字段默认只序列化(read_only)
3) 设置反序列化所需的 系统、局部钩子、全局钩子 等校验规则
"""


class V2Bookserializers(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = ('name', 'img', 'price', 'authors', 'publish', 'publish_name', 'get_author')
        extra_kwargs = {
            'img': {
                'read_only': True
            },
            'publish_name': {
                'read_only': True
            },
            'get_author': {
                'read_only': True
            },
            'name': {
                'max_length': 10,
                'min_length': 3,
                'error_messages': {
                    'max_length': '姓名最长10位',
                    'min_length': '姓名最短3位',
                    'required': '姓名必填'
                }
            }
        }

    def validate_name(self, value):
        if 'g' in value:
            raise exceptions.ValidationError('你这个鸡贼')
        return value

    def validate(self, attrs):
        book_obj = models.Book.objects.filter(name=attrs.get('name'), publish=attrs.get('publish'))
        if book_obj:
            raise exceptions.ValidationError({'name': '同一出版社书名不能重复'})
        return attrs

再次提醒:

  自定义连表深度(自定义属性)默认为read_only只参加序列化

##### 视图层:views.py

```python
class V2Book(APIView):
    # 单局部改:对 v2/books/(pk)/ 传的数据,数据字段key都是选填
    # 群局部改:对 v2/books/ 
    # 请求数据 - [{pk:1, name:123}, {pk:3, price:7}, {pk:7, publish:2}]
    def patch(self, request, *args, **kwargs):
        request_data = request.data
        pk = kwargs.get('pk')

        # 将单改,群改的数据都格式化成 pks=[要需要的对象主键标识] | request_data=[每个要修改的对象对应的修改数据]
        if pk and isinstance(request_data, dict):  # 单改
            pks = [pk, ]
            request_data = [request_data, ]
        elif not pk and isinstance(request_data, list): # 群改
            pks = []
            for dic in request_data:  # 遍历前台数据[{pk:1, name:123}, {pk:3, price:7}, {pk:7, publish:2}],拿一个个字典
                pk = dic.pop('pk', None)
                if pk:
                    pks.append(pk)
                else:
                    return Response({
                        'status': 1,
                        'msg': '数据有误',
                    })
        else:
            return Response({
                'status': 1,
                'msg': '数据有误',
            })

        # pks与request_data数据筛选,
        # 1)将pks中的没有对应数据的pk与数据已删除的pk移除,request_data对应索引位上的数据也移除
        # 2)将合理的pks转换为 objs
        objs = []
        new_request_data = []
        for index, pk in enumerate(pks):
            try:
                # pk对应的数据合理,将合理的对象存储
                obj = models.Book.objects.get(pk=pk)
                objs.append(obj)
                # 对应索引的数据就需要保存下来
                new_request_data.append(request_data[index])
            except:
                # 重点:反面教程 - pk对应的数据有误,将对应索引的data中request_data中移除
                # index = pks.index(pk)
                # request_data.pop(index)
                continue

        book_ser = serializers.V2BookModelSerializer(instance=objs, data=new_request_data, partial=True, many=True)
        book_ser.is_valid(raise_exception=True)
        book_objs = book_ser.save()

        return Response({
            'status': 0,
            'msg': 'ok',
            'results': serializers.V2BookModelSerializer(book_objs, many=True).data
        })
```
 

 

 

 

 

原文地址:https://www.cnblogs.com/asdaa/p/11689849.html