基于django的序列化

1.序列化组件

前后端分离不能直接返回对象,json只能序列化列表和字典,所以我们在jango中使用序列化组件。

首先要导入利用我们安装好的djangorestframework(后面简称drf)中的一些模块。

from rest_framework import APIView # 我们重写的cbv继承APIview的一些方法和属性

from rest_framework.serializers import Serializer # 序列化的类,帮助我们使用序列化

from rest_framework.response import Response  # 继承了HttpRespose,1.传字典使其序列化2.将数据返回给前端页面

django自带的序列化组件(不推荐使用):

from django.core import serializers # django自带的序列化组件
from rest_framework.views import APIView

class Books(APIView):
    
    def get(self, request):
        response = {'code':100, 'msg': '查询成功'}
        books = models.Book.objects.all()
        ret = serializers.serialize('json', books)
        return HttpResponse(ret)

得到的结果:

难以控制json返回的信息。

使用drf的序列化组件:

1.新建一个序列化类继承Serializer

2.在类中要序列化的字段

在新建文件app01serializer中序列化要序列化的字段。 

from app01 import models
from rest_framework import serializers


class BookSerializer(serializers.Serializer):
    book_name = serializers.CharField()
    price = serializers.CharField()

 

在视图中使用序列化的类:

1.实例化序列化的类产生的对象,在产生对象的时候,传入需要序列化的对象。

2.对象.data

3.return Response(对象.data)

 在视图中:

class Books(APIView):

    def get(self, request):
        response = {'code': 100, 'msg': '查询成功'}
        books = models.Book.objects.all()
        # ret = serializers.serialize("json", books)
        # 如果序列化多条,many=True(是queryset对象就要写)
        # 如果序列化一条,many=False,也可以不写
        bookser = BookSerializer(books, many=True)
        return HttpResponse(bookser)

为何many=true为序列化多条源码分析:

如果many=true执行 cls.many_init(*args, **kwargs).

调用Respose:

from rest_framework.response import Response


class Books(APIView):

    def get(self, request):
        response = {'code': 100, 'msg': '查询成功'}
        books = models.Book.objects.all()
        # ret = serializers.serialize("json", books)
        # 如果序列化多条,many=True(是queryset对象就要写)
        # 如果序列化一条,many=False,也可以不写
        bookser = BookSerializer(books, many=True)
        return Response(bookser.data)  # data并不是一个字符串,是一个对象,

结果:返回一个列表。

[
    {
        "book_name": "apple",
        "price": "12.00"
    },
    {
        "book_name": "banana",
        "price": "3.00"
    }
]

将数据放到字典中就可以得到一个简易版本的cbv:

class Books(APIView):

    def get(self, request):
        response = {'code': 100, 'msg': '查询成功'}
        books = models.Book.objects.all()
        # ret = serializers.serialize("json", books)
        # 如果序列化多条,many=True(是queryset对象就要写)
        # 如果序列化一条,many=False,也可以不写
        bookser = BookSerializer(books, many=True)
        print(type(bookser.data))
        response['data'] = bookser.data
        return Response(response)

.data为一个对象类型,将这个对象作为字典的值。

高级用法:

source:可以指定字段(name publish.name),可以指定方法

SerializerMethodField搭配方法使用:(get_字段名字)

publish_detail = serializers.SerializerMethodField(read_only=True)

def get_authors(self, obj):
    ret = AuthorSerializer(instance=obj.authors.all(), many=True)
    return ret.data

read_only:反序列化时,不传

write_only:序列化时,不显示

利用source='name5',修改序列化模型表中的字段名(保证安全性,是字段名不暴露给外界)。


class BookSerializer(serializers.Serializer):
    #指定source='name' ,表示序列化模型表中的name字段,重名命为name5(name和source='name'指定的name不能重名)
    name5=serializers.CharField(source='name')

source不仅可以指定字段,还可以指定方法:

#如果要取 出版社的city source='publish.city'
publish=serializers.CharField(source='publish.name')

source不但可以指定一个字段,还可以指定一个方法
book_type = serializers.CharField(source='get_xx_display',read_only=True)

# 在模型层新增一个xx的字段
xx=models.IntegerField(choices=((0,'文学类'),(1,'情感类')),default=1,null=True)
# 这个地方隐藏了一个display的方法。

通过1对多获取数据,和通过多对多获取数据。

序列化出版社的详情,指定SerializerMethodField之后,可以对应一个方法,返回什么内容,publish_detail就是什么内容
    publish_detail=serializers.SerializerMethodField(read_only=True)
     #对应的方法固定写法get_字段名
     def get_publish_detail(self,obj):
         print(type(obj))
         return {'name':obj.publish.name,'city':obj.publish.city}

# 通过类的的对象来拿取数据(对于宽展模型表的字段的修改不太友好)
authors = serializers.SerializerMethodField()
    def get_authors(self, obj):
        return [{'name': author.name, 'age': author.age} for author in obj.authors.all()]    

取数据的第二种方式:

# 将外键所关联的表的字段序列化
class AuthorSerializer(serializers.Serializer):
    name = serializers.CharField()
    age = serializers.IntegerField()
    


    # 不必通过多对多关系,直接查询表的数据
    def get_authors(self, obj):     
        authorser = AuthorSerializer(obj.authors.all(), many=True)
        return authorser.data

 

 wiite_only=True:序列化的字段不显示(页面不显示该字段)

read_only=True 反序列化的时候,该字段不传

2.序列化的两种方式

Serializers:没有指定表模型

source:指定要序列化哪个字段,可以是字段,可以是方法

SerializerMethodField的用法

# 序列化出版社的详情,指定SerializerMethodField之后,可以对应一个方法,返回什么内容,publish_detail就是什么内容
    publish_detail=serializers.SerializerMethodField(read_only=True)
     # 对应的方法固定写法get_字段名
     def get_publish_detail(self,obj):
         return {'name':obj.publish.name,'city':obj.publish.city}

#返回所有作者信息
    authors=serializers.SerializerMethodField(read_only=True)
     def get_authors(self,obj):
         # return [ {'name':author.name,'age':author.age} for author in obj.authors.all()]
         authorser=AuthorSerializer(obj.authors.all(),many=True)
         return authorser.data

 

ModelSerializers:指定了表模型

class Meta:
                model=表模型
                #要显示的字段
                fields='__all__'
                fields=('id','name')或fields=['id', 'name']
                #要排除的字段
                exclude=('name')
                #深度控制
                depth=1

重写某个字段:

在Meta外部,重写某些字段,方式同Serializers

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model=models.Book
        # fields=('nid','name')
        #不能跟fields同时使用
        # exclude=['name',]
        fields='__all__'
        #深度是1,官方建议不要超过10,个人建议不要超过3
        # depth=1
    # xx=serializers.CharField(source='get_xx_display')
    # authors=serializers.SerializerMethodField()
    # def get_authors(self,obj):
    #     ret=AuthorSerializer(instance=obj.authors.all(),many=True)
    #     return ret.data
    # name=serializers.CharField()

fields 表示显示那几个字段;exclude标识除了指定字段,其他都显示;depth表示跨表查显示,depth=1表示查一张相关联的表的信息(所有信息都会被显示出来),比较难以控制,而且depth查多张表,影响性能。

3.反序列化

Serializers:没有指定表模型

使用继承了Serializers序列化类的对象,反序列化
            -在自己写的序列化类中重写create方法
            -重写create方法,实现序列化
                -在序列化类中:
                    def create(self, validated_data):
                        ret=models.Book.objects.create(**validated_data)
                        return ret
                -在视图中:
                    def post(self,request):
                        bookser=BookSerializer(data=request.data)
                        if bookser.is_valid():
                            ret=bookser.create(bookser.validated_data)
                        return Response()

ps:继承了Serializers,就要重写create和update方法(方法名不能为save,必须为create或update)因为save会重写继承的save方法:

判断用create方法或update方法:

不能走save方法的原因:

序列化逻辑:

class BookSerializer(serializers.Serializer):
    # source=book_name 修改模型表中的book_name字段名,修改的字段名和指定的字段名不能重复
    name = serializers.CharField(source='book_name')
    price = serializers.DecimalField(max_digits=8, decimal_places=2)
    # book_type = serializers.CharField(source='get_classification_display', write_only=True) # 影响is_valid校验不过去,因为与模型表类型不同,且对应的值不一样
    publish_detail = serializers.SerializerMethodField(read_only=True)
    def get_publish_detail(self, obj):
        return {'name':obj.publish.name, 'city':obj.publish.city}
    # authors = serializers.SerializerMethodField(read_only=True)
    def get_authors(self, obj):
        # return [{'name': author.name, 'age': author.age} for author in obj.authors.all()]
        authorser = AuthorSerializer(obj.authors.all(), many=True)
        return authorser.data

    def create(self, validated_data): # 函数名必须为create
        ret=models.Book.objects.create(**validated_data)
        return ret

视图层逻辑:

class Books(APIView):

    def get(self, request):
        response = {'code': 100, 'msg': '查询成功'}
        books = models.Book.objects.all()
        # ret = serializers.serialize("json", books)
        # 如果序列化多条,many=True(是queryset对象就要写)
        # 如果序列化一条,many=False,也可以不写
        bookser = BookSerializer(books, many=True)
        print(type(bookser.data))
        response['data'] = bookser.data
        return Response(response)

    # 反序列化
    def post(self, request):
        # 实例化产生一个序列化的对象,data是要反序列化的字典
        print(request.data)
        bookser = BookSerializer(data=request.data)
        # print(bookser.is_valid())
        if bookser.is_valid(raise_exception=True):
            bookser.save()
            # 这里的save方法,本质上就是create方法,所以要在序列化的时候重写save方法
        return Response()

ModelSerializers:指定了表模型

使用继承了ModelSerializers序列化类的对象,反序列化
            -在视图中:
                def post(self,request):
                    bookser=BookSerializer(data=request.data)
                    if bookser.is_valid():
                        ret=bookser.save()
                    return Response()

ModelSerializers在自己类中写了ceate和update方法,所以我们用的时候不必重写这两个方法。

Ps: 在从postman传传数据的时候,不能根据本表的外键关系,来添加数据,分析发现 is_valid(), 将这个表外键关系对应的表的信息自动过滤,解决这个问题,要我们自己在后端手动将这个id,添加到validdated_data.

 

4.反序列化的校验

-validate_字段名(self,value):
            -如果校验失败,抛出ValidationError(抛出的异常信息需要去bookser.errors中取)
            -如果校验通过直接return value


-validate(self,attrs)
            -attrs所有校验通过的数据,是个字典
            -如果校验失败,抛出ValidationError
            -如果校验通过直接return attrs

一般在ModelSerializersz 内指定字段名(不建议使用__all__),使用全局钩子和局部钩子做校验。

#反序列化的校验(局部校验,全局校验)
    def validate_name(self,value):

        print(value)
        raise exceptions.ValidationError('不能以sb开头')
        # if value.startswith('sb'):
        #     raise ValidationError('不能以sb开头')
        # return value

    def validate(self,attrs):
        print(attrs)
        # if attrs.get('price')!=attrs.get('xx'):
        #     raise exceptions.ValidationError('name和price相等,不正常')
        return attrs

因为我们用drf,遵循rest_ful规范,所以后端做校验的时候,在后端抛出异常信息。

 

#使用继承了ModelSerializers序列化类的对象,反序列化
    def post(self,request):
        #实例化产生一个序列化类的对象,data是要反序列化的字典
        bookser=BookSerializer(data=request.data)
        # bookser.data
        if bookser.is_valid(raise_exception=True):  # 给前端抛出异常
            #清洗通过的数据
            bookser.save()
        else:  # 后端抛出异常
            print(bookser.errors['name'][0])
        return Response()

钩子函数通过is_valid()这个入口函数进行如下源码校验:

 

校验字段:

5.源码阅读

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值