首页 > 其他分享 >drf之序列化组件

drf之序列化组件

时间:2023-02-05 20:56:12浏览次数:38  
标签:serializers name length 组件 CharField 序列化 data drf

drf之序列化组件

模型类准备

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)
    publisher = models.CharField(max_length=32)

迁移后随便插入几条数据就可以简单的测试接口了。

序列化器介绍与快速使用

在写接口时,需要序列化,需要反序列化,而且反序列化的过程中要做数据校验

---》drf直接提供了固定的写法,只要按照固定写法使用,就能完成上面的三个需求。

drf提供了两个类,Serializer、ModelSerializer,使用这些类也能完成并进一步简化接口的编写。

序列化类基本使用--Serializer

序列化类的建立

编写一个serializer.py文件

from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    # 序列化某些字段,这里写要序列化的字典
    name = serializers.CharField()  # serializers下大致跟models下的类是对应的
    price = serializers.CharField()
    publish = serializers.CharField()

我们在文件中建立继承序列化器的类,在内部添加需要序列化和反序列化的字段。

使用序列化类进行序列化

在views.py中,我们可以在函数中,可以调用序列化类BookSerializer产生序列化对象

查询数据

# 视图文件
class BookView(APIView):
    def get(self, request):
        books = Book.objects.all()
        # 使用序列化类来完成---》得有个序列化类
        # instance要序列化的数据books queryset对象
        # many=True 只要是queryset对象要传many=True,如果是单个对象就不用传
        ser = BookSerializer(instance=books, many=True)
        return Response(ser.data)  # 无论是列表还是字典都可以序列化
    
class BookDetailView(APIView):
    # def get(self, request,pk):
    def get(self, request, *args, **kwargs):
        book = Book.objects.filter(pk=kwargs.get('pk')).first()
        # 序列化
        ser = BookSerializer(instance=book)
        return Response(ser.data)
    
# url文件
urlpatterns = [
    path('books/', views.BookView.as_view()),
    path('books/<int:pk>/', views.BookDetailView.as_view()),
]

序列化对象中:

  • 用于查询的序列化对象,需要初始化instance参数,接收查询结果
  • 查询结果如果是queryset则many参数要设置为True,如果是数据对象则不需要
  • 序列化对象初始化后,在data属性中会将数据对象或queryset序列化车成字典或列表
  • 利用Response可以直接将data的列表或字典都能序列化成json格式

关于视图类:

  • 我们通常将对单和对多操作分成两个视图类,这样我们就可以在路由层直接分路,不必在如get函数中再添加判断

路由层:

  • 不需要后续添加pk参数的,让视图BookView处理
  • 需要后续添加pk参数的,让视图BookDetailView处理

使用序列化类进行反序列化

serializer反序列化可以帮助我们直接校验数据是否合法,然后直接做出新增或修改的操作。

新增数据

# 序列化类
class BookSerializer(serializers.Serializer):
    # 序列化某些字段,这里写要序列化的字典
    name = serializers.CharField()  # serializers下大致跟models下的类是对应的
    price = serializers.CharField()
    publish = serializers.CharField()

    def create(self, validated_data):
        # 保存的逻辑
        # validated_data 校验过后的数据 {name,price,publish}
        # 保存到数据库
        book = Book.objects.create(**validated_data)
        # 一定不要返回新增的对象
        return book
    
# 视图类
class BookView(APIView):
    def post(self, request):
        # requset.data  # 前端提交的要保存的数据----》校验数据---》存
        ser = BookSerializer(data=request.data)  # 把前端传入的要保存的数据,给data参数
        # 校验数据
        if ser.is_valid():
            # 保存---->需要自己写,要在序列化类BookSerializer中写----》create方法
            ser.save()  # 调用ser.save,自动触发咱们写的create,保存起来
            return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})

序列化类中写create,在校验后会自动执行新增。

  • create函数会接收validated_data参数,保存的是校验成功的数据
  • 在上述代码中,因为序列化的字段和模型类相对应,所以可以直接使用打散

视图类中写post函数表示执行新增:

  • 初始化序列对象加入data参数接收request.data,它会在校验处理后传入validated_data
  • 根据BookSerializer初始化传入的参数中没有instance,判断为新增,在ser.save()中自动执行序列化类中的create

修改数据

# 序列化类
class BookSerializer(serializers.Serializer):
    # 序列化某些字段,这里写要序列化的字典
    name = serializers.CharField()  # serializers下大致跟models下的类是对应的
    price = serializers.CharField()
    publish = serializers.CharField()

    def update(self, instance, validated_data):
        # instance 要修改的对象
        # validated_data 校验过后的数据
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        instance.save()  # orm的单个对象,修改了单个对象的属性,只要调用对象.save,就能把修改保存到数据库
        return instance  # 不要忘了吧修改后的对象,返回
    
# 视图类
class BookDetailView(APIView):
    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        # 反序列化保存 ---借助于序列化类
        ser = BookSerializer(data=request.data, instance=book)
        if ser.is_valid():
            ser.save()  # 由于没有重写update,所以这报错
            return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})

序列化类使用update,在校验后自动执行:

  • instance接收修改的实例数据对象
  • validated_data接收校验后合法的数据
  • instance注意用save保存,才能在数据库生效
  • 将修改后的instance返回出去,最终会传给序列化对象的data属性

视图类使用put表示修改动作:

  • put中先查询得到一个数据对象,再传入序列化类的instance
  • data同新增,将body中的数据处理好传入
  • 产生的序列化对象根据instance有值,save时自动执行了update

基于序列化编写5个接口

在上文已经编写了查多、查单、新增、修改,而关于删除是不需要序列化组件参与的,其总体的内容如下:

点击查看代码
# 序列化类
from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    # 序列化某些字段,这里写要序列化的字典
    name = serializers.CharField()  # serializers下大致跟models下的类是对应的
    price = serializers.CharField()
    publish = serializers.CharField()
    
    def create(self, validated_data):
        # 保存的逻辑
        # validated_data 校验过后的数据 {name,price,publish}
        # 保存到数据库
        book = Book.objects.create(**validated_data)
        # 一定不要返回新增的对象
        return book
    
    def update(self, instance, validated_data):
        # instance 要修改的对象
        # validated_data 校验过后的数据
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        instance.save()  # orm的单个对象,修改了单个对象的属性,只要调用对象.save,就能把修改保存到数据库
        return instance  # 不要忘了吧修改后的对象,返回
    
    
# 视图类
class BookView(APIView):
    def get(self, request):
        books = Book.objects.all()
        # 使用序列化类来完成---》得有个序列化类
        # instance要序列化的数据books queryset对象
        # many=True 只要是queryset对象要传many=True,如果是单个对象就不用传
        ser = BookSerializer(instance=books, many=True)
        return Response(ser.data)  # 无论是列表还是字典都可以序列化
    
    def post(self, request):
        # requset.data  # 前端提交的要保存的数据----》校验数据---》存
        ser = BookSerializer(data=request.data)  # 把前端传入的要保存的数据,给data参数
        # 校验数据
        if ser.is_valid():
            # 保存---->需要自己写,要在序列化类BookSerializer中写----》create方法
            ser.save()  # 调用ser.save,自动触发咱们写的create,保存起来
            return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})
        
class BookDetailView(APIView):
    # def get(self, request,pk):
    def get(self, request, *args, **kwargs):
        book = Book.objects.filter(pk=kwargs.get('pk')).first()
        # 序列化
        ser = BookSerializer(instance=book)
        return Response(ser.data)
    
    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        # 反序列化保存 ---借助于序列化类
        ser = BookSerializer(data=request.data, instance=book)
        if ser.is_valid():
            ser.save()  # 由于没有重写update,所以这报错
            return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})
    
    def delete(self, requset, pk):
        Book.objects.filter(pk=pk).delete()
        return Response({'code': 100, 'msg': '删除成功'})

反序列化类校验

在上文中,我们在post和put函数中对request.data中的数据进行了is_valid的校验。

ps:实际上由于有全局异常捕获,我们可以直接用is_valid(raise_exception=True)校验,那么校验失败的话会直接报错。

而反序列化时,是基于什么标准进行校验的呢?

  1. 先执行serializer字段自己的校验规则如max_length
  2. 再validators参数=[方法1,方法2,],方法可以是自定义的,也可以用django.core.validators.RegexValidator
  3. 局部钩子校验规则
  4. 全局钩子校验规则

钩子函数

# 序列化类
	# 局部钩子
    def validate_name(self, name):
        # 校验name是否合法
        if name.startswith('sb'):
            # 校验不通过,抛异常
            raise ValidationError('不能以sb开头')
        else:
            return name
        
    # 全局钩子
    def validate(self, attrs):
        # 校验过后的数据,书名跟出版社名字不能一致
        if attrs.get('name') == attrs.get('publish'):
            raise ValidationError('书名跟出版社名字不能一致')
        else:
            return attrs

验证器

序列化类常用字段

1 BooleanField	      BooleanField()

2 NullBooleanField	  NullBooleanField()

3 CharField	CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)

4 EmailField	EmailField(max_length=None, min_length=None, allow_blank=False)

5 RegexField	RegexField(regex, max_length=None, min_length=None, allow_blank=False)

6 SlugField	SlugField(max_length=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+

7 URLField	URLField(max_length=200, min_length=None, allow_blank=False)

8 UUIDField	UUIDField(format=’hex_verbose’) format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"

9 IPAddressField	IPAddressField(protocol=’both’, unpack_ipv4=False, **options)

10 IntegerField	IntegerField(max_value=None, min_value=None)

11 FloatField	FloatField(max_value=None, min_value=None)

12 DecimalField	DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置

13 DateTimeField	DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)

14 DateField	DateField(format=api_settings.DATE_FORMAT, input_formats=None)

15 TimeField	TimeField(format=api_settings.TIME_FORMAT, input_formats=None)

16 DurationField	DurationField()

17 ChoiceField	ChoiceField(choices) choices与Django的用法相同

18 MultipleChoiceField	MultipleChoiceField(choices)

19 FileField	FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)

20 ImageField	ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)

ListField	ListField(child=, min_length=None, max_length=None)
DictField	DictField(child=)


重点:
CharField  IntegerField  DecimalField  DateTimeField BooleanField
ListField  DictField

序列化类字段常用参数

CharField及其子类的(EmailField) ---》反序列化的校验,字段自己的规则

参数 含义
max_length/min_length 最大长度/最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符

IntegerField的常用参数:max_value/min_value

所有字段都有的参数:

参数 含义
required 表明该字段在反序列化时必须输入,默认True
default 反序列化时的默认值
allow_null 表明该字段是否允许传入None,默认False
validators 该字段使用的验证器
---- ----
error_messages 包含错误编号与错误信息的字典
label 用于HTML展示API页面时,显示的字段名称
help_text 用于HTML展示API页面时,显示的字段帮助提示信息
**** ****
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,默认False

序列化定制

所谓定制就是可以一定程度上改写序列化的规则,控制序列化数据的形式

数据准备

# 创建关联表
class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)

    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)  # 留住,还有很多
    authors = models.ManyToManyField(to='Author')


class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)


class Author(models.Model):
    name = models.CharField(max_length=32)
    phone = models.CharField(max_length=11)

# 迁移,录入数据

source方法

配置序列化字段的参数source

  • 自有字段,直接写字段名字
    name_real = serializers.CharField(max_length=8, source='name')

  • 关联字段,一对多的关联,直接点
    publish = serializers.CharField(source='publish.name')

  • 多对多,搞不了,source不能用
    authors=serializers.CharField(source='authors.all')

# 序列化类
class BookSerializer(serializers.Serializer):
    # 字段参数,通用的,所有字段都可以写  通过source指定哪个字段
    # 自有字段,直接写字段名字
    name_real = serializers.CharField(max_length=8, source='name')
    real_price = serializers.CharField(source='price')

    # 关联字段,一对多的关联,直接点
    publish = serializers.CharField(source='publish.name')

    #多对多,搞不了,source不能用
    # authors = serializers.CharField(source='authors.all')	

ps:source用到了反射的原理,当传入的实例(queryset或者orm对象)有source参数的字段属性,那么则以这个字段属性的数据做序列化。

SerializerMethodField定制

class BookSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=8)
    price = serializers.CharField()

    publish_detail = serializers.SerializerMethodField()

    def get_publish_detail(self, obj):
        return {'name': obj.publish.name, 'addr': obj.publish.addr}

    author_list = serializers.SerializerMethodField()

    def get_author_list(self, obj):
        return [{'name': author.name, 'phone': author.phone} for author in obj.authors.all()]
  • 上述代码中,将一对多的外键,序列化成字典,内容为外键表的详情
  • 将多对多的外键,序列化成列表套字典,内容为多个外键数据详情字典的列表

表模型中定制

#### 模型表中,写两个函数伪装成数据属性(可以不伪装)
class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)

    publish = models.ForeignKey(to='Publish', on_delete=models.SET_NULL) 
    authors = models.ManyToManyField(to='Author')

    @property
    def publish_detail(self):
        return {'name': self.publish.name, 'addr': self.publish.addr}

    @property
    def author_list(self):
        return [{'name': author.name, 'phone': author.phone} for author in obj.authors.all()]
    
    
 # 序列化类
class BookSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=8)
    price = serializers.CharField()

    # publish_detail = serializers.CharField()
    publish_detail = serializers.DictField()
    author_list = serializers.ListField()
  • 原理就是模型表中的属性,序列化表都会对其进行反射取资源,那么方法也一样是模型表的属性之一,严谨来说加装property更清晰
  • 对于定制的序列化,我们如果想让其成为方便操作的字典和列表(自定义对象和数组),则使用serializers.DictField()和serializers.ListField()

标签:serializers,name,length,组件,CharField,序列化,data,drf
From: https://www.cnblogs.com/Leethon-lizhilog/p/17093925.html

相关文章