DRF之序列化组件

2023-12-24 19:32:02

目录

一、序列化组件介绍

二、序列化类的使用

三、序列化类快速使用

四、?序列化类反序列化校验

【使用步骤】?

五、序列化类保存和修改

【保存】

【修改】

六、常用序列化字段和参数

【1】常用字段

【2】常用参数

七、序列化高级用法之soruce

八、序列化高级用法之定制返回字段

【1】多表关联序列化

【2】多表关联反序列化

九、ModelSerializer使用


一、序列化组件介绍

序列化类(组件)可以干的事:

  1. 序列化 qs对象,单个对象 做序列化给前端
  2. 反序列化数据校验:前端传入数据---> 校验数据是否合法
  3. 反序列化---> 前端传入数据,存到数据库中
  • DRF(Django REST framework)是一个用于构建基于 Django 的 Web API 的强大框架。
    • 在 DRF 中,序列化组件是其中一个核心组件,用于在 API 请求和响应中处理数据的转换和验证。
  • 序列化组件的主要功能是将复杂的数据结构(例如模型对象)转换为可以序列化(序列化为 JSON、XML 等格式)和传输的数据,并且能够根据所需的数据结构对传入的数据进行反序列化,还原为程序可操作的对象。

二、序列化类的使用

1 写个py文件,叫serializer.py
2 写个类,继承serializers.Serializer
3 在类中写要序列化的字段

from rest_framework import serializers
class PublishSerializer(serializers.Serializer):
    # 写字段,要序列化的字段
    name = serializers.CharField()
    addr = serializers.CharField()
    id = serializers.IntegerField()

4 在视图类中使用,完成序列化

多条
    ser = PublishSerializer(instance=publish_list, many=True) ??? ?
    ser.data ?# 序列化后的数据
单条:
    ser = PublishSerializer(instance=publish) ??? ?
    ser.data ?# 序列化后的数据
  • 参数
    • instance : 实例(对象)
    • data : 数据
    • many=True : 如果是queryset对象,一般都是必须加
    • many=False : 如果是 .first() 一般不写,默认不写是 False
  • 序列化的结果
    • data = book_ser.data
      • 将 book_ser 转成字典 -- 列表套字典
    • data的类型是
      • <class 'rest_framework.utils.serializer_helpers.ReturnList'>

三、序列化类快速使用

视图类

from .serializer import PublishSerializer


class PublishView(APIView):
    def get(self, request):
        publish_list = Publish.objects.all()
        ser = PublishSerializer(instance=publish_list, many=True)  
        # 如果序列化多条,要many=True
        return Response({'code': 100, 'msg': '查询所有成功', 'results': ser.data})

class PublishDetailView(APIView):
    def get(self, request, pk):
        publish = Publish.objects.filter(pk=pk).first()
        ser = PublishSerializer(instance=publish)  # 单个不写many=True
        return Response(
            {'code': 100, 'msg': '查询单条成功', 'results': ser.data})

序列化类

from rest_framework import serializers
class PublishSerializer(serializers.Serializer):
    # 写字段,要序列化的字段
    name = serializers.CharField()
    # addr = serializers.CharField()
    id = serializers.IntegerField()

路由

urlpatterns = [
    path('publish/', views.PublishView.as_view()),
    path('publish/<int:pk>', views.PublishDetailView.as_view()),
]

四、?序列化类反序列化校验

序列化类可以做字段校验---> 三层
第一层:字段自己的serializers.CharField(max_length=12,min_length=3)

第二层:局部钩子

def validate_name(self, name):
    # 待校验的前端传入的name的数据
    if name.startswith("sb"):
        # 不行,抛异常
        raise ValidationError('不能以sb开头')
    return name

全局钩子--> 前端多传的,这里不会有

def validate(self, attrs):
    print(attrs)
    # 多个字段同时校验
    # 出版社名和地址不能一样---》出版社前3个字不能和地址前3个字一样
    if attrs.get('name')[:3] == attrs.get('addr')[:3]:
        raise ValidationError('出版社名和地址不能一样')
    return attrs

【使用步骤】?

写序列化类:写三层规则

视图类中:

ser = PublishSerializer(data=request.data) ?# 把待校验数据传入
if ser.is_valid(): ?# 做数据校验---> 三层
    print(ser.data)
else:
    print(ser.errors) ?# 没有校验通过,打印错误信息

五、序列化类保存和修改

【保存】

1 在序列化类中,必须重写 create,完成真正的保存

"""保存,必须重写create"""
def create(self, validated_data):
    # validated_data 校验过后的数据---》多传的数据,在这没有
    publish = Publish.objects.create(**validated_data)
    return publish ?
# 不要忘了返回新增的对象---> 后续会拿着这个对象做序列化 ?ser.data--->根据它做序列化的

2 在视图类中,数据校验通过后,调用ser.save()
ser.save() ?# 使用序列化类保存--> 会报错---> 我们没有指定保存到那个表--> 必须重写create方法

【修改】

修改功能,也要校验和保存

1 在序列化类中,必须重写 update,完成真正的修改

def update(self, instance, validated_data): ?# {name:上海出版社,add:上海地址}
    instance.name = validated_data.get('name')
    instance.addr = validated_data.get('addr')
    instance.save() # publish 对象的save---> 保存到数据中
    return instance


2 视图类中
?? ??? ?ser = PublishSerializer(instance=publish, data=request.data)
?? ??? ?ser.save() # 虽然新增或修改都是调用save,但是内部做了判断

六、常用序列化字段和参数

【1】常用字段

字段字段构造方式详解
BooleanFieldBooleanField()布尔字段用于存储和表示真/假值。构造方法不需要参数。
NullBooleanFieldNullBooleanField()可空布尔字段是可以接受三个值的布尔字段:True、False和None(空值)。构造方法不需要参数。
CharFieldCharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)字符字段用于存储短文本数据。max_length指定字符的最大长度,min_length指定最小长度。allow_blank指定是否允许为空值。trim_whitespace指定是否在保存数据前去除首尾的空格。
EmailFieldEmailField(max_length=None, min_length=None, allow_blank=False)Email字段用于存储和验证电子邮件地址。max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。
RegexFieldRegexField(regex, max_length=None, min_length=None, allow_blank=False)正则表达式字段用于存储和验证符合特定模式的数据。regex指定正则表达式,max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值
SlugFieldSlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+Slug字段用于存储URL友好的文本标识符。max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。
URLFieldURLField(max_length=200, min_length=None, allow_blank=False)URL字段用于存储和验证URL地址。max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。
UUIDFieldUUIDField(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"UUID字段用于存储和验证通用唯一标识符。format参数指定UUID的格式。
IPAddressFieldIPAddressField(protocol=’both’, unpack_ipv4=False, **options)IP地址字段用于存储和验证IP地址。protocol参数指定所允许的IP地址协议类型,unpack_ipv4参数指定是否拆分IPv4地址。
IntegerFieldIntegerField(max_value=None, min_value=None)整数字段用于存储整数值。max_value指定最大值,min_value指定最小值。
FloatFieldFloatField(max_value=None, min_value=None)浮点数字段用于存储浮点数值。max_value指定最大值,min_value指定最小值。
DecimalFieldDecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置十进制字段用于存储精确的十进制数值。max_digits指定最多位数,decimal_places指定小数点位置。coerce_to_string指定是否将值强制转化为字符串形式。max_value指定最大值,min_value指定最小值。
DateTimeFieldDateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)日期时间字段用于存储日期和时间。format参数指定日期时间的输出格式,input_formats参数指定输入格式。
DateFieldDateField(format=api_settings.DATE_FORMAT, input_formats=None)日期字段用于存储日期。format参数指定日期的输出格式,input_formats参数指定输入格式。
TimeFieldTimeField(format=api_settings.TIME_FORMAT, input_formats=None)时间字段用于存储时间。format参数指定时间的输出格式,input_formats参数指定输入格式。
DurationFieldDurationField()持续时间字段用于存储一段时间的持续时间。构造方法不需要参数。
ChoiceFieldChoiceField(choices) choices与Django的用法相同选择字段用于存储和验证预定义选项中的一个值。choices参数指定可选的选项值。
MultipleChoiceFieldMultipleChoiceField(choices)多选字段用于存储和验证多个预定义选项中的值。choices参数指定可选的选项值。
FileFieldFileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)文件字段用于上传和保存文件。max_length指定文件名的最大长度,allow_empty_file指定是否允许为空文件。use_url指定是否使用文件的URL路径。
ImageFieldImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)图片字段用于上传和保存图片文件。max_length指定文件名的最大长度,allow_empty_file指定是否允许为空文件。use_url指定是否使用图片的URL路径。
ListFieldListField(child=, min_length=None, max_length=None)列表字段用于存储和验证列表类型的数据。child参数指定列表中元素的类型,min_length指定最小长度,max_length指定最大长度。
DictFieldDictField(child=)字典字段用于存储和验证字典类型的数据。child参数指定字典中value的类型。
  • 总结:常用字段
IntegerField      
CharField   
DateTimeField  
DecimalField
 
ListField和DictField

【2】常用参数

(1) 选项参数:(CharField,IntegerField)

参数名称作用
max_length校验,最大长度
min_lenght检验,最小长度
allow_blank是否允许为空
trim_whitespace去掉前后的空白
max_value最小值
min_value最大值

(2) 通用参数

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

七、序列化高级用法之soruce

1 修改字段,映射字段

# publish_name表中不存在
publish_name = serializers.CharField(source='name')

2 修改字段,映射方法

# sb_name是表模型中一个方法
name = serializers.CharField(source='sb_name')

3 修改字段,跨表查询

# book表中可以链表查询
publish=models.ForeignKey(to='Publish.name')

八、序列化高级用法之定制返回字段

【1】多表关联序列化

# 定制序列化返回的字段格式
	-方案一:在表模型中写,在序列化类中映射  (可以使用source)
    	# models.py
        def publish_detail(self):
        	return {'name': self.publish.name, 'city': self.publish.city}
        # serializer.py
        	publish_detail = serializers.DictField()
        # 前端看到
            "publish_detail": {
                "name": "北京出版社",
                "city": "北京"
            }
    -方案二:在序列化类中写SerializerMethodField,必须配合一个方法 get_字段名,方法返回什么,前端就看到什么
    	# Serializer.py
            publish_detail = serializers.SerializerMethodField()
            def get_publish_detail(self, obj):
                return {'name': obj.publish.name, 'city': obj.publish.city}
        # 前端看到
            "publish_detail": {
                "name": "北京出版社",
                "city": "北京"
            }

models.py

from django.db import models


class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)

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

    def __str__(self):
        return self.name
    # def book_name(self):
    #     return self.name+'sb'
    # def publish_detail(self):
    #     return {'name': self.publish.name, 'city': self.publish.city}
    #
    # def author_list(self):
    #     l = []
    #     for author in self.authors.all():
    #         l.append({'name': author.name, 'age': author.age})
    #     return l


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)

    def __str__(self):
        return self.name


class AuthorDetail(models.Model):
    telephone = models.BigIntegerField()
    birthday = models.DateField()
    addr = models.CharField(max_length=64)


class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '出版社'
        verbose_name_plural = verbose_name

views.py

class BookView(APIView):
    def get(self, request):
        obj = Book.objects.all()
        ser = BookSerializer(instance=obj, many=True)

        '''
        [
            {
                "name": "西游记",
                "price": "66.00",
                "publish_detail": {name:名字,city:城市},
                "authors_list":[{name:名字,age:19}]
            },
    
        ]
        
        '''
        return Response(ser.data)
### 定制返回字段 ###
class BookSerializer(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.CharField()
    # 定制返回字段---》方案一:在表模型中写方法,在序列化类中做映射
    # publish_detail = serializers.CharField()  # publish_detail 会映射表模型中 publish_detail方法,方法返回值是 字典,强行用CharField字符串接收
    # publish_detail = serializers.DictField()  # publish_detail 会映射表模型中 publish_detail方法,方法返回值是 字典,用DictField接收
    # author_list = serializers.ListField()

    # 定制返回字段---》方案二:在序列化类中写  SerializerMethodField
    # 只要写了这个字段类SerializerMethodField,必须配合一个方法:get_字段名,这个方法返回什么,前端这个字段就显示什么
    publish_detail = serializers.SerializerMethodField()

    def get_publish_detail(self, obj):
        # 当前序列化到的book对象
        return {'name': obj.publish.name, 'city': obj.publish.city}

    author_list = serializers.SerializerMethodField()

    def get_author_list(self, obj):
        l = []
        for author in obj.authors.all():
            l.append({'name': author.name, 'age': author.age})
        return l

    book_name = serializers.SerializerMethodField()
	
    def get_book_name(self, obj):
        return obj.name + 'sb'

【2】多表关联反序列化

反序列化保存
使用同一个序列化类会出现

  • 序列化字段和反序列化字段不一致
  • 序列化字段:
    • name
    • price
    • publish_detail
    • author_list
  • 反序列化字段:
    • name
    • price
    • publish
    • author
  • 如果是共同的,不需要额外处理
  • 如果是不同的,需要通过字段参数控制
    • read_only?? ?表明该字段仅用于序列化输出,默认False,序列化过程
    • write_only?? ?表明该字段仅用于反序列化输入,默认False,反序列化过程

serializer.py

class BookSerializer(serializers.Serializer):
    name = serializers.CharField()  # 公共的
    price = serializers.CharField()  # 公共的
    publish = serializers.IntegerField(write_only=True)  # 只用来做反序列化
    authors = serializers.ListField(write_only=True)  # 只用来做反序列化

    publish_detail = serializers.SerializerMethodField(read_only=True)  # 只用来做序列化
    author_list = serializers.SerializerMethodField(read_only=True)  # 只用来做序列化

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

    def get_author_list(self, obj):
        l = []
        for author in obj.authors.all():
            l.append({'name': author.name, 'age': author.age})
        return l

    def create(self, validated_data):
        # {name,price,publish:1,authors:[1,2]}
        authors = validated_data.pop('authors')
        book = Book.objects.create(name=validated_data.get('name'), price=validated_data.get('price'),
                                   publish_id=validated_data.get('publish'))
        book.authors.add(*authors)
        return book

    def update(self, instance, validated_data):
        # {name,price,publish:1,authors:[1,2]}
        authors = validated_data.pop('authors')
        validated_data['publish_id'] = validated_data.pop('publish')
        for key in validated_data:
            setattr(instance, key, validated_data[key])

        instance.save()
        # 先清空在放入
        # instance.authors.clear()
        # instance.authors.add(*authors)
        # 直接存
        instance.authors.set(authors)
        return instance

views.py

class BookView(APIView):

    def post(self, request):
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)


class BookDetail(APIView):
    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)

urls.py

urlpatterns = [
    path('books/', views.BookView.as_view()),
    path('books/<int:pk>/', views.BookDetail.as_view()),
]

注:多表反序列化校验 --> 跟之前一样?

九、ModelSerializer使用

之前写的序列化类,继承了serializers.Serializer,跟表没有必然联系
ModelSerializer跟表一一对应,以后基本需要重写create和update

serializer.py

### 继承ModelSerializer --->少写代码
class BookSerializer(serializers.ModelSerializer):
    # name = serializers.CharField(max_length=18,min_length=3)  # 公共的
    # price = serializers.CharField()  # 公共的
    # publish = serializers.IntegerField(write_only=True)  # 只用来做反序列化
    # authors = serializers.ListField(write_only=True)  # 只用来做反序列化
    # 上述操作,通过 Meta实现了

    # 扩写的字段,也要在fields注册
    # 方式二:定制字段
    # publish_detail = serializers.SerializerMethodField(read_only=True)  # 只用来做序列化
    # author_list = serializers.SerializerMethodField(read_only=True)  # 只用来做序列化
    # def get_publish_detail(self, obj):
    #     return {'name': obj.publish.name, 'city': obj.publish.city}
    # def get_author_list(self, obj):
    #     l = []
    #     for author in obj.authors.all():
    #         l.append({'name': author.name, 'age': author.age})
    #     return l

    # 方式二:定制字段方式一
    # publish_detail = serializers.DictField(read_only=True)
    # author_list = serializers.ListField(read_only=True)
    class Meta:
        model = Book  # 写了这两句,会把表模型中Book,所有字段映射过来
        # fields='__all__'
        fields = ['name', 'price', 'publish', 'authors', 'publish_detail', 'author_list']
        extra_kwargs = {  # 给某个或某几个字段设置字段属性
            'name': {'max_length': 18, 'min_length': 3},
            'publish': {'write_only': True},
            'authors': {'write_only': True},
            'publish_detail': {'read_only': True},
            'author_list': {'read_only': True},
        }

    # 一般不需要写create和update了---> ModelSerializer帮我们实现了
    # 局部钩子和全局钩子,该怎么写还怎么写
    # def validate_name(self,name):
    #     pass

文章来源:https://blog.csdn.net/qq_53842456/article/details/135184231
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。