序列化器

序列化组件

1.简单介绍

  • 序列化:序列器会把模型转成字典,经过response以后变成json字符串
  • 反序列化:把客户端传过来的数据,经过request以后变成字典,序列化器可以把字典转成模型

2.使用

  • 建立orm,创建一个py文件,写一个序列化器,继承Serializer
  • 在类中书写序列化的字段
  • 在视图中导入实例化得到的序列化类的对象,把要序列化的对象传入进去
  • 序列化类的对象.data 这里是一个字典
  • 把字典返回,如果不适应rest_framework提供的Response,l可以使用JsonResponse
# ser.py
from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    price = serializers.CharField() #创建你要序列化的字段


# views.py
class BookAPIView(APIView):
    def get(self, request, pk):
        book = models.Book.objects.filter(id=pk).first()
        book_ser = BookSerializer(book) # 要序列化谁就把谁传过来, # 调用类的__init__
        return Response(book_ser.data) # 序列化对象.data就是序列化后的字典
#url
re_path('books/(?P<pk>\d+)', views.BookAPIView.as_view()),

补充:还有很多的字段类型

CharField,IntegerField,DateField

3. 单个数据的修改和展示

上面是简单的使用,这个是对某一个数据的更新。

  • 在类中写要序列化的字段,像序列化哪个就写哪个,里面还可以添加一些参数

    	max_length	最大长度
        min_lenght	最小长度
        allow_blank	是否允许为空
        trim_whitespace	是否截断空白字符
        max_value	最小值
        min_value	最大值
    
  • 在视图中使用,实例化得到序列化的对象,把要修改的对象传入,修改的数据传入

  • 校验数据,通过保存

  • 如果字段的校验规则不够我们可以自己写钩子


# ser.py
class BookSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=6,min_length=2)
    price = serializers.CharField()
    author = serializers.CharField(max_length=6,min_length=2)
    publish = serializers.CharField(max_length=6,min_length=2)
    
# view.py
class BookAPIView(APIView):
    def put(self,request,pk):
        response_msg = {'state':100,'msg':'成功'}
        book = models.Book.objects.filter(id=pk).first()
        # 更新或修改某个字段要传两个参数
        book_obj = BookSerializer(instance=book,data=request.data) # 传两个参数对象和数据
        # 验证数据
        if book_obj.is_valid():
            # 这里不能直接用save要重写
            book_obj.save()
            response_msg['data']=book_obj.data
        else:
            response_msg['state']=101
            response_msg['msg'] = '数据校验失败'
            response_msg['data']=book_obj.errors
        return Response(response_msg)



3.1 ser.py中的局部钩子和全局钩子

from rest_framework.exceptions import ValidationError
    # 局部钩子
    def validate_author(self, data):
        if '啊' in data:
            raise ValidationError('作者名不能有啊')
        else:
            return data

    def validate(self, validate_data):
        author = validate_data.get('author')
        publish = validate_data.get('publish')
        if author==publish:
            raise ValidationError('作者名字不能和出版社一样哦')
        else:
            return validate_data

3.2 重写update方法

  • 我们在修改数据的时候用save(),不能直接保存,需要我们重新在ser.py中重写update方法
 def update(self, instance, validated_data):
        instance.name = validated_data.get('title')
        instance.price = validated_data.get('price')
        instance.author = validated_data.get('author')
        instance.publish = validated_data.get('publish')
        instance.save()
        return instance

  • instance 是book这个对象

  • validated_data是校验过的数据

  • instance.save()相当于book.save()

{
    "state": 101,
    "msg": "数据校验失败",
    "data": {
        "non_field_errors": [
            "作者名字不能和出版社一样哦"
        ]
    }
}

drf返回错误信息的标准写法,要有返回的错误信息

3.3 read_only 和write_only

  • read_only 表明该字段只用于序列化输出,默认是False,设置成True,在postman里面可以看到该字段,修改的时候不需要传该字段

    # get方法序列化的时候输出
    
    {
        "title": "西游记",
        "price": "22",
        "author": "你得到",
        "publish": "西方出版社"
    }
    
    # put方法反序列化的时候输入
    {
        "title": "西游记",
        "price": "22",
        "publish": "北方出版社"
    }
    
  • write_only 表明该字段只用于反序列化输入的时候,默认是False,设置成True,在postman里面看不到该字段,修改需要修改

    展示时
    {
        "title": "西游记",
        "price": "22",
        "publish": "西方出版社"
    }
    修改时
    {
        "title": "西游记",
        "price": "22",
        "publish": "西方出版社",
        "author":"南门吹雪"
    }
    

4 查询所有和新增数据

4.1 查看所有

class BooksAPIView(APIView):

    def get(self, request):
        response_msg = {'state': 100, 'msg': '成功'}
        books = models.Book.objects.all()
        books_ser = BookSerializer(books, many=True)#这里我们要查所有的字段要加参数many
        response_msg['data'] = books_ser.data
        return Response(response_msg)

  • 这里为什么要加参数呢

4.2 many的源码


    def __new__(cls, *args, **kwargs):

        if kwargs.pop('many', False):
            return cls.many_init(*args, **kwargs)
        return super().__new__(cls, *args, **kwargs)

这里对象没有生成之前调用__new__方法,生成空对象,触发__init__,__new__控制对象的生成

  • 先去BookSerializer去找_new__方法没有到父类,找到__new__方法
  • 从kwrags取出参数pop,many默认是False,因为我们设置many是True执行下面的return,正常的实例化,many_init
 @classmethod
    def many_init(cls, *args, **kwargs):
        list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer)
        return list_serializer_class(*args, **list_kwargs)

我们看到这个他是一个list,每一个都是BookModelSerializer对象

4.3 新增数据


    def post(self,request):
        response_msg = {'state': 100, 'msg': '成功'}
        book_ser = BookSerializer(data=request.data)
        if book_ser.is_valid():
            book_ser.save()
           def create(self, validated_data):
        isinstance = models.Book.objects.create(**validated_data)
        return isinstance

这里也遇到一个问题要重新写create方法才能保存

4.4 create方法的重写

   def create(self, validated_data):
        isinstance = models.Book.objects.create(**validated_data)
        return isinstance

4.5 删除数据

  def delete(self, request, pk):
        models.Book.objects.filter(pk=pk).delete()
        response_msg = {'state': 100, 'msg': '成功'}
        return Response(response_msg)

5. 模型化类器

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = '__all__' # 序列化所有
        exclude = ('title') # 排除title序列化其他字段,不能和fileds连用
         extra_kwargs = {  # 类似于这种形式name=serializers.CharField(max_length=16,min_length=4)
            'price': {'write_only': True},
        }
        

  • 在3.2之后的模型类中write_only_fields弃用了

其他该写上面参数写什么参数,也可以不用重新写create和update方法

6. 自己封装Response

7. Serializer高级用法

SerializerMethodField()的使用的使用

{
    "title": "西游记",
    "price": "12",
    "pub_date": "2020-07-28",
    "publish": "Publish object",
    "authors": "app01.Author.None"
}

当我们跨表查询的时候,发现出版社和作者是一个对象,我们要在后端把他取出来实例化展示

  	authors = serializers.SerializerMethodField()
    
    def get_authors(self,instance):
        authors = instance.authors.all()
        authors_list = []
        for author in authors:
            authors_list.append({'name':author.name,'age':author.age})

        return authors_list

  • 先定义一个列表,取出所有的作者,for循环把所有的作者用字典的形式添加到里面

source的使用

  • 1 可以改字段名字 xxx=serializers.CharField(source='title')

  • 2 可以.跨表publish=serializers.CharField(source='publish.email')

  • 3 可以执行方法pub_date=serializers.CharField(source='test') test是Book表模型中的方法

它里面默认的book.authors

posted @ 2020-07-08 09:19  小子,你摊上事了  阅读(110)  评论(0编辑  收藏  举报