Django REST Framework——3. 序列化器(Serializer)

文章目录

  • 一、序列化与反序列化
    • 1.1 序列化过程
    • 1.2 反序列化过程
  • 二、字段类型及参数
    • 2.1 常用字段
    • 2.2 选项参数
    • 2.3 核心参数
  • 三、数据校验
    • 3.1 is_vaild()方法
    • 3.2 局部校验(只涉及一个字段)
    • 3.3 全局校验(涉及多个字段)
    • 3.4 validators参数
  • 四、数据操作
    • 4.1 查询单条数据
    • 4.2 查询所有数据
    • 4.3 新增数据
    • 4.4 修改数据
    • 4.5 删除数据
  • 五、模型类序列化器(Model Serializer)
    • 5.1 定义
    • 5.2 指定字段
    • 5.3 添加额外参数
  • 六、SerializerMethodField字段

**序列化器(Serializer) **可以帮助我们更加轻松的实现:

  • 序列化:将复杂数据(如查询集和模型实例对象)转换为本机 Python 数据类型,然后可以轻松地转换为JSONxml 或者其他内容类型;

  • 反序列化:将JSONxml等转换回原来的python数据类型。

DRF序列化器的用法与Django Form表单的用法极为相似,它提供了SerializerModelSerializer类,帮助我们处理模型实例和查询集的序列化与反序列化,并提供了一些强大的功能。

一、序列化与反序列化

1.1 序列化过程

我们通过实现“获取一本书的信息”这样一个需求,来学习序列化过程。在搭建好环境之后:

  1. 创建模型类:

    from django.db import models
    
    class Book(models.Model):
        title = models.CharField(max_length=30, verbose_name="书籍名称")
        author = models.CharField(max_length=20, verbose_name="作者")
        price = models.DecimalField(
            max_digits=5, decimal_places=2, verbose_name="价格")
        publisher = models.CharField(max_length=20, verbose_name="出版社")
    
        class Meta:
            verbose_name = "书籍"
            verbose_name_plural = "书籍"
    
  2. 创建序列化类,继承serializers.Serializer,与django Form表单的写法类似:

    from rest_framework import serializers
    
    class BookSerializer(serializers.Serializer):
        title = serializers.CharField()
        author = serializers.CharField()
        price = serializers.DecimalField(max_digits=5, decimal_places=2)
        publisher = serializers.CharField()
    

    序列化类的字段与django的模型类字段基本对应,定义方法也基本一致。

  3. 编写视图,需要继承APIView,返回DRF的Response(序列化对象.data)对象或者返回django的JsonResponse(序列化对象.data)对象:

    from rest_framework.response import Response
    from rest_framework.views import APIView
    from quickstart.models import Book
    from quickstart.serializers import BookSerializer
    
    
    class BookView(APIView):
        def get(self, request, id):
            book = Book.objects.filter(id=id).first()
            # 实例化序列化器类,传入需要序列化的对象
            book_serializer = BookSerializer(book)
            # book_serializer.data存放着序列化之后的数据
            return Response(book_serializer.data)
    
  4. 添加路由:

    from django.contrib import admin
    from django.urls import include, path
    
    from quickstart.views import BookView
    
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('book//', BookView.as_view())
    ]
    

之后,我们随便添加几本书籍到数据库。然后访问路径book/1/,就能看到id为1的书籍信息了(JSON格式)。

1.2 反序列化过程

反序列化过程同样很简单,我们在上面代码的基础之上,通过实现“修改一本书的信息”这样一个需求,来学习反序列化过程。

  1. 在视图中,获取模型对象并生成序列化器对象:

    class BookView(APIView):
    
        def put(self, request, id):
            response_content = {"code":200, "msg":"修改成功!"}
            book = Book.objects.filter(id=id).first()
            # 生成序列化器对象,传入模型对象和前端提交的数据即可
            book_serializer = BookSerializer(book, request.data)
            # 如果提交的数据通过校验,就进行保存
            if book_serializer.is_valid():
                book_serializer.save()
                response_content["data"] = book_serializer.data
                return Response(response_content)
            else:
                response_content["code"] = 400
                response_content["msg"] = "修改失败!"
                response_content["data"] = book_serializer.errors
                return Response(response_content)
    
  2. 上面代码第10行中的sava()方法,依赖于create()update()方法中的一个或两个,但这两个方法被定义为抽象方法(因为对模型对象的创建和修改依赖于具体场景),所以需要我们要自己实现,否则会报错。

    至于save()具体会用到create()还是update()取决于实例化序列器时是否传入了已有的模型实例

    由于我们在实例化序列化器时,传入了一个已存在的Book实例对象,所以save()会用到update(),我们就需要实现该方法:

    class BookSerializer(serializers.Serializer):
        ……
    
        def update(self, instance, validated_data):
            # instance就是已存在的Book实例对象
            instance.title = validated_data.get("title")
            instance.author = validated_data.get("author")
            instance.price = validated_data.get("price")
            instance.publisher = validated_data.get("publisher")
            # 由于实例对象是模型对象,所以需要调用模型对象的save方法保存到数据库
            instance.save()
            return instance
    

之后,我们就可以对书籍信息进行修改了。

二、字段类型及参数

2.1 常用字段

序列化器的绝大部分字段与django的模型类字段是对应的,定义方法也基本一致,所以不再展开解释,详细的可以参考官方文档:

序列化器字段 字段构造方式
BooleanField BooleanField()
NullBooleanField NullBooleanField()
CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugField SlugField(max_length=50, min_length=None, allow_blank=False)
URLField URLField(max_length=200, min_length=None, allow_blank=False)
UUIDField UUIDField(format=‘hex_verbose’) format: 1) 'hex_verbose'"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2)
IPAddressField IPAddressField(protocol=‘both’, unpack_ipv4=False, **options)
IntegerField IntegerField(max_value=None, min_value=None)
FloatField FloatField(max_value=None, min_value=None)
DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)
DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DurationField DurationField()
ChoiceField ChoiceField(choices)
MultipleChoiceField MultipleChoiceField(choices)
FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
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)

2.2 选项参数

参数名称 作用
max_length 最大长度
min_lenght 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符
max_value 最小值
min_value 最大值

2.3 核心参数

下面这些参数时各字段通用的:

  • read_only:

    表示该字段是只读的,只在序列化时使用该字段,而在反序列化期间创建或更新实例时不使用该字段。假如在反序列化时,传入了该字段,则会被忽略。

    默认为False

  • write_only:

    表示该字段是只写的,与read_only恰好相反,表示只在反序列化期间创建或更新实例时使用该字段,序列化期间不使用。

​ 默认为False

read_onlywrite_only参数在某些情况下很有用。比如,有时候我们进行反序列化时,某些字段是不需要前端提交的,我们就可以将其设置为read_only,允许前端不提交该字段的值。

  • required:

    如果反序列化期间未提供字段,通常会引发错误;如果反序列化过程中不需要此字段,则设置为false。

    默认为True

  • allow_null:

    表明是否允许传入None。

    默认为False

  • default:

    反序列化时使用的默认值。

    注意:设置default值意味着该字段不是必需的。同时包含default和required关键字参数都是无效的,并且会引发错误。

  • source:

    该参数接受一个模型类属性,该属性会被用于生成序列化器类的字段。

    该参数的默认值为字段的名称。所以,当我们没有传入该参数,并且字段名称与模型类的所有属性名称都不匹配时,就会报错。

    class BookSerializer(serializers.Serializer):
        """
        模型类中的属性名称为 title,所以下面的代码会报错
        book_name = serializers.CharField() 
        """
        # 这里通过source指定了正确的属性名称,所以不会报错
        book_name = serializers.CharField(source="title")
    

    它也可以传入只接受一个self参数的方法,该方法定义在模型类中,其返回值会被传给该字段。例如:

    url = URLField(source='get_absolute_url')
    

    还可以跨表查询,比如通过图书查询作者,再通过作者查询作者邮箱:

    email = EmailField(source='author.email')
    

    另外,source='*'有特殊含义,代表将整个对象传递给该字段。这对于创建嵌套表示或对于需要访问完整对象才能确定输出表示的字段很有用。

  • validators:

    验证器函数列表,应将其应用于输入字段。

    验证器函数应该引发验证错误或简单地返回。

  • error_messages:

    包含错误编号与错误信息的字典。

  • label:

    用于HTML展示API页面时,显示的字段名称。

  • help_text:

    用于HTML展示API页面时,显示的字段帮助提示信息。

更多字段和参数请参考官方文档:传送门

三、数据校验

3.1 is_vaild()方法

使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象

在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。

  • 验证成功:通过序列化器对象的**validated_data属性获取数据**;
  • 验证失败:通过序列化器对象的**errors属性获取错误信息**,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。

is_valid()方法还可以在验证失败时抛出serializers.ValidationError异常,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。

serializer.is_valid(raise_exception=True)

DRF自带的校验方法不够强大,但它允许我们通过以下三种方法自定义校验方法:

3.2 局部校验(只涉及一个字段)

如果只对单个字段进行校验,我们可以通过向序列化器类中添加validate_字段名称方法实现自定义字段级别的验证。这些类似于Django表单中的clean_字段名称方法:

from rest_framework import serializers
from rest_framework.exceptions import ValidationError

class BookSerializer(serializers.Serializer):
    ……
    
	def validate_price(self, value):
    	"""局部校验price字段,参数value就是price字段的值"""
    	# 数据不合乎要求就抛出ValidationError异常
    	if float(value) < 10:
        	raise ValidationError("价格过低,不能低于10元")
        # 符合要求就直接返回
    	else:
        	return value

3.3 全局校验(涉及多个字段)

如果要同时对多个字段进行校验,可以定义validate方法来验证:

from rest_framework import serializers
from rest_framework.exceptions import ValidationError

class BookSerializer(serializers.Serializer):
    ……
    
    def validate(self, attrs):
        if attrs["author"] == attrs["publisher"]:
            raise ValidationError("作者姓名与出版社名称相同!")
        else:
            return attrs

3.4 validators参数

在字段中添加validators选项参数,指定验证器函数(可以有多个),就会用验证器函数校验该字段。

def about_django(value):
    if 'django' not in value.lower():
        raise serializers.ValidationError("图书不是关于Django的")

class BookSerializer(serializers.Serializer):
    """图书数据序列化器"""
    btitle = serializers.CharField(label='名称', max_length=20, validators=[about_django])  # 注意:validators的实参是列表
    ……

四、数据操作

4.1 查询单条数据

我们在上面序列化过程中所展示的就是查询单条数据的过程。

4.2 查询所有数据

与查询单条数据不同,如果要序列化多个实例,则需要在实例化序列化器时,传入many=True参数。

class BooksView(APIView):
    def get(self, request):
        """返回所有书籍"""
        books = Book.objects.all()
        books_serializer = BookSerializer(books, many=True)
        response_content = {"code": 200, "msg": "获取成功!",
                            "data": books_serializer.data}
        return Response(response_content)

4.3 新增数据

class BookView(APIView):
	……
    
    def post(self, request):
        """新增一本书籍"""
        # 传入request.data,对前端数据提交的数据反序列化
        book_serializer = BookSerializer(data=request.data)
        # 务必要先验证,切记!!!
        if book_serializer.is_valid():
            book_serializer.save()
            resonse_content = {"code": 200,"data":book_serializer.data}
        else:
            resonse_content = {"code": 400, "data": book_serializer.errors}
        return Response(resonse_content)

调用了序列化器的save方法,就要实现create()方法,切记!!!

class BookSerializer(serializers.Serializer):
    ……

    def create(self, validated_data):
        # validated_data就是经过验证的前端提交的数据
        return Book.objects.create(**validated_data)  # 注意拆包

4.4 修改数据

修改的过程,就是上面的反序列化的过程。与新增不同的地方在于实例化序列化器时,多传入了一个已存在的模型实例对象,需要我们手动实现的是update()方法,而非create()方法。

4.5 删除数据

一般情况下,不会用到序列化器,通过模型类直接删除即可。

class BookView(APIView):
    ……

    def delete(self, request, id):
        Book.objects.filter(id=id).delete()
        return Response({"code":200, "msg":"删除成功!"})

五、模型类序列化器(Model Serializer)

之前,我们的Serializer类继承了serializer.Serializer,需要手动一个个写入字段,较为麻烦。所以,DRF我们提供了ModelSerializer类来帮助我们快速创建一个Serializer类。

继承了ModelSerializer类的Serializer类有以下特点:

  • 基于模型类自动生成一系列字段
  • 基于模型类自动为Serializer生成验证器,比如unique_together
  • 包含默认的create()update()的实现,不用我们去实现。

5.1 定义

class BookSerializer(serializers.ModelSerializer):
    # 不需要编写字段
    class Meta:
        # 指定模型类
        model = Book  # Book模型类需要导入
        # 指定序列化器包含模型类的哪些字段,这里为全部字段
        fields="__all__"  # 前后双下划线

模型类序列化器虽然不需要编写字段,但如果需要,还是允许我们编写一些额外的字段或者覆盖自动默认的字段

5.2 指定字段

  • 使用fields指定Serializer类包含模型类的哪些字段,除了__all__表名包含所有字段,还可以指定部分字段。
    比如:fields = ('id', 'title', 'price')

    另外,fields中可以写模型类的方法名(包括自定义的),序列化器会自动调用该方法,将方法名作为键,返回值作为值。

  • 使用exclude可以明确排除掉哪些字段。
    比如:exclude = ('image',)

  • 通过read_only_fields指明只读字段,即仅用于序列化输出的字段。
    比如:read_only_fields = ('id', 'bread', 'bcomment')

write_only_fields已被extra_kwargs所替代。

5.3 添加额外参数

使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数。比如:

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ('id', 'title', 'price', 'author',)
        extra_kwargs = {
            'price': {'min_value': 10, 'required': True},
            'author': {'write_only': True},
        }

六、SerializerMethodField字段

这是一个只读字段。接受一个方法,并将该方法的返回值添加到对象的序列化表示中。比如:

class BookSerializer(serializers.Serializer):
    ……

    def new_author(self, instance):
        return "花城最帅了"

    author = serializers.SerializerMethodField("new_author")

在此之后,所有序列化输出中的author对应的值,就都成了“花城最帅了”。

值得注意的是,如果在实例化SerializerMethodField类时不指定方法名称,则默认调用名称为get_的方法。也就是说,上面代码中的new_author得修改为get_author

你可能感兴趣的:(django框架,django,python,后端,restful)