drf-序列化器和解析器

解析器

作用

将前端传来的数据按照规定格式解析成后端相应数据格式。

JsonParser

json格式解析器
前端发送格式:
在这里插入图片描述

后端接收格式以及解析格式:
在这里插入图片描述

FormParser

表单数据解析器
前端发送格式:
在这里插入图片描述

后端接收格式以及解析格式:
在这里插入图片描述

MultiPartParser:

解析多部分的HTML表单内容,支持文件上传
前端发送格式:
在这里插入图片描述

后端接收格式以及解析格式:
在这里插入图片描述

FileUploadParser

解析原始文件上传内容。此时, request.data 属性将是一个字典,并且只包含一个键,这个键叫做 ‘file’ ,对应的值包含上传的文件内容。

如果使用FileUploadParser解析器的视图,在被调用的时候URL中携带一个 filename 关键字参数,则该参数将被用作文件名。如果在没有这个关键字参数的情况下调用它,则客户端必须在HTTP头部的 Content-Disposition 中设置文件名。

前端发送格式:
在这里插入图片描述

在这里插入图片描述

后端接收格式以及解析格式:
在这里插入图片描述

源码解析

进入APIView的dispatch看源码
在这里插入图片描述
在这里插入图片描述
由源码可知在initialize_request初始化视图类配置的解析类以及一些跳转的配置
在这里插入图片描述
在这里插入图片描述

但是没有看到哪里调用解析类去解析前端发来的数据?那么就接着看源码,因为Request初始化了parsers成员变量,那么直接搜索parsers变量在哪里使用过,就搜到了Request类下的_parse接口,看代码大意就是返回解析的数据和文件
在这里插入图片描述
接着搜_parse是哪里调用,接着就找到_load_data_and_files,进而找到是调用打data时才解析数据_load_data_and_files
在这里插入图片描述

序列化器

应用场景

数据校验

内置校验
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers


class InfoSerializer(serializers.Serializer):
    title = serializers.CharField(required=True, max_length=20, min_length=6)
    order = serializers.IntegerField(required=False, max_value=100, min_value=10)
    level = serializers.ChoiceField(choices=[("1", "高级"), (2, "中级")])


class InfoView(APIView):
    def post(self, request):
        ser = InfoSerializer(data=request.data)
        if ser.is_valid():
            return Response(ser.validated_data)
        else:
            return Response(ser.errors)
正则校验
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from django.core.validators import RegexValidator, EmailValidator


class InfoSerializer(serializers.Serializer):
    title = serializers.CharField(required=True, max_length=20, min_length=6)
    order = serializers.IntegerField(required=False, max_value=100, min_value=10)
    level = serializers.ChoiceField(choices=[("1", "高级"), (2, "中级")])

    email = serializers.CharField(validators=[EmailValidator(message="邮箱格式错误")])

    more = serializers.CharField(validators=[RegexValidator(r"\d+", message="格式错误")])

    code = serializers.CharField()


class InfoView(APIView):
    def post(self, request):
        ser = InfoSerializer(data=request.data)
        if ser.is_valid():
            return Response(ser.validated_data)
        else:
            return Response(ser.errors)
钩子校验
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework import exceptions


class InfoSerializer(serializers.Serializer):
    title = serializers.CharField(required=True, max_length=20, min_length=6)
    order = serializers.IntegerField(required=False, max_value=100, min_value=10)
    code = serializers.CharField()

    def validate_code(self, value):
        if len(value) > 6:
            raise exceptions.ValidationError("字段钩子校验失败")
        return value

    def validate(self, attrs):
        return attrs


class InfoView(APIView):
    def post(self, request):
        ser = InfoSerializer(data=request.data)
        if ser.is_valid():
            return Response(ser.validated_data)
        else:
            return Response(ser.errors)
Model校验
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework import exceptions
from api import models
from django.core.validators import RegexValidator


class RoleSerializer(serializers.ModelSerializer):
    more = serializers.CharField(required=True)

    class Meta:
        model = models.Role
        fields = ["title", "order", "more"]
        extra_kwargs = {
            "title": {"validators": [RegexValidator(r"\d+", message="格式错误")]},
            "order": {"min_value": 5},
        }

    def validate_more(self, value):
        return value

    def validate(self, attrs):
        return attrs


class InfoView(APIView):
    def post(self, request):
        ser = RoleSerializer(data=request.data)
        if ser.is_valid():
            return Response(ser.validated_data)
        else:
            return Response(ser.errors)
校验+保存
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework import exceptions
from api import models
from django.core.validators import RegexValidator


class RoleSerializer(serializers.ModelSerializer):
    more = serializers.CharField(required=True)

    class Meta:
        model = models.Role
        fields = ["title", "order", "more"]
        extra_kwargs = {
            "title": {"validators": [RegexValidator(r"\d+", message="格式错误")]},
            "order": {"min_value": 5},
        }# 定义的字段额外添加属性

    def validate_more(self, value):
        return value

    def validate(self, attrs):
        return attrs


class InfoView(APIView):
    def post(self, request):
        ser = RoleSerializer(data=request.data)
        if ser.is_valid():
            ser.validated_data.pop("more")  # 数据库没有的字段需要删除,避免报错
            instance = ser.save()  # ser.save(v1=123,v2=234)
            return Response(ser.validated_data)
        else:
            return Response(ser.errors)
校验+保存+FK+M2M

序列化器会将外键数据以对象的方式传回,比如Depart对象,如果是m2m,那么就会返回列表,列表中包含tag对象

from django.db import models


class Role(models.Model):
    title = models.CharField(verbose_name="标题", max_length=32)
    order = models.IntegerField(verbose_name="顺序")


class Tag(models.Model):
    caption = models.CharField(verbose_name="名称", max_length=32)


class UserInfo(models.Model):
    name = models.CharField(verbose_name="姓名", max_length=32)
    gender = models.SmallIntegerField(verbose_name="性别", choices=((1, "男"), (2, "女")))
    role = models.ForeignKey(verbose_name="角色", to="Role", on_delete=models.CASCADE)
    ctime = models.DateTimeField(verbose_name="创建时间", auto_now_add=True)

    tags = models.ManyToManyField(verbose_name="标签", to="Tag")

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework import exceptions
from api import models
from django.core.validators import RegexValidator
import datetime


class UserInfoSerializer(serializers.ModelSerializer):
    more = serializers.CharField(required=True)

    class Meta:
        model = models.UserInfo
        fields = ["name", "gender", "role", "tags", "more"]
        extra_kwargs = {
            "name": {"validators": [RegexValidator(r"n-\d+", message="格式错误")]},
        }

    def validate_more(self, value):
        return value

    def validate(self, attrs):
        return attrs


class InfoView(APIView):
    def post(self, request):
        ser = UserInfoSerializer(data=request.data)
        if ser.is_valid():
            ser.validated_data.pop("more")
            instance = ser.save(ctime=datetime.datetime.now())
            return Response("成功")
        else:
            return Response(ser.errors)
外键id问题

外键不一定只能使用depart来获取/存储跨表的值,只要名称符合数据库里面字段的命名规则,也可以通过自定义字段来读取/存储外键数据
在这里插入图片描述

M2M自定义问题

在这里插入图片描述
传入的是列表,里面包含整数

假如像上图一样返回999和990,那么保存到数据库的就是
在这里插入图片描述
如果希望存储的是tag对象,那么就要在钩子函数中获取数据库中是否有对应的tag对象,然后返回queryset
在这里插入图片描述

数据序列化

使用体验跟Django原生的ModelForm和Form相似

序列化过程
  1. 运行django项目,创建字段对象
  2. 运行django项目创建类(利用metaclass)
  3. 用户请求到来,数据库获取数据 + 序列化类
  4. 触发序列化-当前类 ser.data
serializer.Serializer
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from api import models


class InfoSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField()
    order = serializers.IntegerField()


class InfoView(APIView):
    def get(self, request):
        # 1.数据库获取多条数据
        # queryset = models.Role.objects.all()
        # ser = InfoSerializer(instance=queryset, many=True)

        # 2.数据库获取单条数据
        instance = models.Role.objects.all().first()
        ser = InfoSerializer(instance=instance, many=False)
        
        return Response(ser.data)
serializer.ModelSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from api import models


class InfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        # fields = "__all__"
        # fields = ['id', 'title', 'order']
        exclude = ["id"]


class InfoView(APIView):
    def get(self, request):
        # 1.数据库获取多条数据
        # queryset = models.Role.objects.all()
        # ser = InfoSerializer(instance=queryset, many=True)

        # 2.数据库获取单条数据
        instance = models.Role.objects.all().first()
        ser = InfoSerializer(instance=instance, many=False)
        return Response(ser.data)

ModelModelSerializerSerializer中都可以自定义字段,并传入一些相关参数。

class InfoSerializer(serializers.ModelSerializer):
    gender = serializers.CharField(source="get_gender_display")
    role = serializers.CharField(source="role.title")
    ctime = serializers.DateTimeField(format="%Y-%m-%d")
    other_name = serializers.CharField(source="name")
    mine = serializers.SerializerMethodField()

    class Meta:
        model = models.UserInfo
        fields = ['id', 'name', 'gender', "role", 'ctime', "other_name", "mine"]

    def get_mine(self, obj):
        return "x-x-{}".format(obj.name)
Foreignkey和ManytoManyField序列化
基于SerializerMethodField自定义方法对关联表数据进行序列化
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from api import models

class InfoSerializer(serializers.ModelSerializer):
    role = serializers.SerializerMethodField()
    tags = serializers.SerializerMethodField()

    class Meta:
        model = models.UserInfo
        fields = ['id', 'name', "role", "tags"]
		
	def get_role(self, obj):
		return "{}-{}".format(obj.id,obj.title)
	
	def get_tags(sekf, obj):
		queryset = obj.tags.all()
        result = [{"id":tag.id, "caption":tag.caption} for tag in queryset]
        return result

class InfoView(APIView):
    def get(self, request):
        queryset = models.UserInfo.objects.all()
        ser = InfoSerializer(instance=queryset, many=True)
        print(type(ser.data), ser.data)
        return Response(ser.data)

基于嵌套的序列化类实现
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from api import models


class RoleSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        # fields = "__all__"
        fields = ["id", 'title']


class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Tag
        fields = "__all__"


class InfoSerializer(serializers.ModelSerializer):
    role = RoleSerializer()
    tags = TagSerializer(many=True)

    class Meta:
        model = models.UserInfo
        fields = ['id', 'name', "role", "tags"]


class InfoView(APIView):
    def get(self, request):
        queryset = models.UserInfo.objects.all()
        ser = InfoSerializer(instance=queryset, many=True)
        print(type(ser.data), ser.data)
        return Response(ser.data)

源码解析

在这里插入图片描述
在这里插入图片描述

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值