Java教程

12_03、drf之序列化和反序列化

本文主要是介绍12_03、drf之序列化和反序列化,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一、序列化器

1、序列化器的作用

序列化器,在Django框架终究是一个类,她的作用就是序列化和反序列化

序列化:序列化会把(数据库中的)模型对象转换成字典,经过response以后变成字符串,传给客户端(前端)

[{"name":"西游记","price":"100.00","author":"吴承恩"}]

反序列化:把客户端(前端)送过来的数据,经过request后,变成字典,序列化器可以把字典再转换成模型,最后再存到数据库中

序列化器在反序列化过程中,会自动完成数据校验(数据是否合法,长度是否足够)。

2、序列化器的使用方式(口头描述)

第一步:写一个类:必须继承drf中的Serializer及其子类
第二步:在类中写要序列化的字段(要序列化哪些,就写哪些,不序列化的可以不写)
第三步:在视图类中使用序列化类
第四步:得到序列化类对象(对象.data),通过Response返回给前端

二、Serializer的使用

1、序列化

(1)简单的serializer实例演示

1. 表模型类

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

2.序列化器

from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.Serializer):
    # max_length=32,min_length=3  反序列化保存校验数据的时候用
    name = serializers.CharField(max_length=8, min_length=3)
    price=serializers.CharField() # models中使用了DecimalField,这个位置使用了CharField会把小数类型转成字符串
    author = serializers.CharField()

3.视图类

from rest_framework.response import Response
from app01.models import Book
from rest_framework.views import APIView
from app01.serializer import BookSerializer

class BookView(APIView):
    def get(self, request):
        # 查出来的数据做序列化
        book_list = Book.objects.all()

        # instance:要序列化的对象  qs,单个对象
        # many:如果是qs对象,many=True,如果是单个对象many=False
        ser = BookSerializer(instance=book_list, many=True)  # 传入初始化的参数instance=None, data=empty
        # ser.data使用模型类对象序列化后的字典
        return Response(ser.data)  # 字典,列表,字符串都行

4.路由

from django.conf.urls import url
from django.contrib import admin
from app01 import views


urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^books/', views.BookView.as_view()),
]

(2)字段类型

models中有自己的字段类型

    name = models.CharField()
    price = models.DecimalField()

序列化器中也有自己的字段类型

    name = serializers.CharField()
    price=serializers.CharField() 

常用的序列化器字段类型:

  CharField
  IntegerField
  FloatField
  DecimalField
  DateTimeField
  DateField

字段大全

字段字段构造方式
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(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
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) 'hex'"5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
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) max_digits: 最多位数 decimal_palces: 小数点位置
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) choices与Django的用法相同
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=)

(3)字段参数

models中有自己的字段参数

    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)

序列化器中也有自己的字段参数

    name = serializers.CharField(max_length=8, min_length=2)

注意

'''
read_only:表明该字段仅用于序列化输出,默认False
  -如果read_only=True,这个字段只用来做序列化---》把对象---》json给前端
write_only:表明该字段仅用于反序列化输入,默认False
  -如果read_only=write_only,这个字段只用来做反序列化---》前端json---》存到数据库'''

选项参数

 

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

通用参数

 

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

 

(4)定制序列化字段

 我们可以通过序列化器自带的方法,自定义我们想要的序列化字段,key(字段名),value(方法返回)都可以定制

比如,作者表和作者详情表(一对一外键关系)

我们可以序列化作者表(作者表里有姓名),并在作者表里自定义作者信息字段

这样我们就可以通过一张表,返回我们想要的(作者,作者信息)序列化数据

方式一:序列化类中定制

from rest_framework import serializers
from app01.models import Book


class BookSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=8, min_length=2)
    price = serializers.CharField()
    author = serializers.CharField()

    # 定制序列化字段re_name
    re_name = serializers.SerializerMethodField()  # 必须配合一个方法,方法名get_字段名

    def get_re_name(self, obj):  # 方法返回什么,字段就是什么,obj是当前序列化到的单个对象
        return str(obj.name) + '重置版'  # python是动态强类型语言--》强类型是:不同类型之间不允许直接运算

    # 定制序列化字段price_info
    price_info = serializers.SerializerMethodField()

    def get_price_info(self, obj):
        return "价格是:" + str(obj.price)

 

 

方式二:models中写字段,serializer中序列化

models

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

    @property
    def re_name(self):
        return str(self.name) + '重置版'

    @property
    def price_info(self):
        return '价格是' + str(self.price)

serializer

class BookSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=8, min_length=2)
    price = serializers.CharField()
    author = serializers.CharField()

    # 在models中写方法,这里字段名就是models的方法名,price_info方法返回什么,这个字段就是什么
    re_name = serializers.CharField()
    price_info = serializers.CharField()

注意:如果是列表,用ListField()方法;如果是字典,用DecimalField()方法

authors=serializers.ListField()
authors_info = serializers.DecimalField()

2、反序列化

(1)反序列化—新增creare

1.反序列化顺序

#   第一步:把前端传入的数据,放到Serializer对象中:ser=BookSerializer(data=request.data)
#   第二步:校验数据:ser.is_valid():
#   第三步:保存,ser.save()---》必须重写create,在序列化类中
    def create(self, validated_data):
        book = Book.objects.create(**validated_data)
        return book

 2.实例演示

视图类

class BookView(APIView):
    # 反序列化
    def post(self, request):
        # 接收前端返回的数据,使用data参数
        ser = BookSerializer(data=request.data)

        # 校验参数
        if ser.is_valid():
            # 如果是true表示数据校验通过,通过,就保存
            # 如果instance为None,调用save本质会调用create--》父类create直接抛异常,所以我们要重写create
            ser.save()
            return Response(ser.data)
        return Response({'code': 101, 'msg': '数据校验失败', 'err': ser.errors})    

序列化器

class BookSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=8, min_length=2)
    price = serializers.CharField()
    author = serializers.CharField()

    # 定制字段:在models中写方法,这里字段名就是models的方法名,price_info方法返回什么,这个字段就是什么
    re_name = serializers.CharField(read_only=True)  # 只序列化
    price_info = serializers.CharField(read_only=True)  # 只序列化

    def create(self, validated_data):
        # validated_data校验过后的数据
        # 手动存到book表中
        book = Book.objects.create(**validated_data)
        # book=Book.objects.create(name=validated_data.get('name'))
        return book  # 不要忘记返回book对象

 

(2)反序列化—查询单条、修改、删除

视图类

class BookDetailView(APIView):
    def get(self, request, pk):
        book = Book.objects.filter(pk=pk).first()  # 查询单条记录
        ser = BookSerializer(instance=book)  # 如果是单条记录,many不传,就是false
        return Response(ser.data)

    def delete(self, request, pk):
        res = Book.objects.filter(pk=pk).delete()  # 删除单条记录
        print(res)
        if res[0] > 0:
            return Response({'code': 100, 'msg': '删除成功'})
        else:
            return Response({'code': 103, 'msg': '数据不存在'})

    def put(self, request, pk):
        # 修改:用什么数据,修改哪个对象?
        book = Book.objects.filter(pk=pk).first()
        # 既有instance,又有data,表示修改
        ser = BookSerializer(instance=book, data=request.data)
        if ser.is_valid():
            # 重写update方法
            ser.save()  # 调用save---》内部根据instance判断是触发create还是update
            return Response(ser.data)
        return Response({'code': 102, 'msg': '修改出错', 'err': ser.errors})

 序列化类

class BookSerializer(serializers.Serializer):
    id = serializers.CharField(read_only=True)
    # max_length=32,min_length=3  反序列化保存校验数据的时候用
    name = serializers.CharField(max_length=8, min_length=3)
    price = serializers.CharField(required=False)  # models中使用了DecimalField,这个位置使用了CharField会把小数类型转成字符串
    author = serializers.CharField(required=False)

    def create(self, validated_data):
        # validated_data校验过后的数据
        # 手动存到book表中

        book = Book.objects.create(**validated_data)
        # book=Book.objects.create(name=validated_data.get('name'))
        return book  # 不要忘记返回book对象

    def update(self, instance, validated_data):
        # validated_data校验过后的数据,instance 是要修改的对象
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.author = validated_data.get('author')
        instance.save()  # 模型对象自带的save,保存到数据库中
        return instance  # 不要忘记返回instance对象

    # 局部钩子
    # 字段有自己的校验:max_length .... ,再校验,就可以写局部钩子
    def validate_name(self, attr):
        # attr就是前端传入的数据
        # 名字不能以sb开头
        if attr.startswith('sb'):
            raise ValidationError("名字不能以sb开头")
        else:
            return attr  # 没有问题,正常返回

路由

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', views.BookView.as_view()),
    path('books/<int:pk>', views.BookDetailView.as_view()),  # 用于查询一个,利用转换器<int:pk>
]

(3)反序列化—局部和全局钩子

虽然序列化器会根据字段参数对字段自动校验,但是某些情况,需要我们主动添加一些校验,这里就要用到局部钩子和全局钩子的概念

from rest_framework.exceptions import ValidationError
    # 局部钩子
    # 字段有自己的校验:max_length .... ,再校验,就可以写局部钩子
    def validate_name(self, attr):
        # attr就是前端传入的数据
        # 名字不能以sb开头
        if attr.startswith('sb'):
            raise ValidationError("名字不能以sb开头")
        else:
            return attr  # 没有问题,正常返回

    # 先走字段自己规则,再走局部钩子,再走全局钩子
    # 全局钩子
    def validate(self, attrs):
        # attrs校验过后的数据
        if attrs.get('name') == attrs.get('author'):
            raise ValidationError('作者名不能等于书名')
        else:
            return attrs

三、ModelSerializer模型类序列化器

模型类序列化器是与表模型是绑定关系,他通过对序列化器的封装,可以让我们省去重写updata、create

1、绑定

# 以后使用ModelSerializer跟表模型做绑定,以后这个用的多,不需要重写update和create方法了
class BookSerializer2(serializers.ModelSerializer):
    class Meta:
        model = Book  # 跟那个表有关系,绑定
        # fields='__all__' # 这是注册的第一种方式,表示序列化所有字段

        fields = ['id', 'name', 'price', 'author', 'price_info']  # 这是注册的第二种方式,序列化自己想要的字段
        # id是从表模型中映射过来的,auto,它会不要求你传
        # price_info:它不是数据库中字段,使我们扩写的字段
        # 注意:即便扩写的字段,也要在fields中注册# 重写字段
  # 局部和全局钩子跟之前一样

2、额外添加参数

# 以后使用ModelSerializer跟表模型做绑定,以后这个用的多,不需要重写update和create方法了
class BookSerializer2(serializers.ModelSerializer):
    class Meta:
        model = Book  # 跟那个表有关系,绑定
        # fields='__all__' # 这是注册的第一种方式,表示序列化所有字段

        fields = ['id', 'name', 'price', 'author', 'price_info']  # 这是注册的第二种方式,序列化自己想要的字段

        # id是从表模型中映射过来的,auto,它会不要求你传
        # price_info:它不是数据库中字段,使我们扩写的字段
        # 注意:即便扩写的字段,也要在fields中注册



        # 原来的字段参数,通过extra_kwargs传进去
        extra_kwargs = {
            'name': {'write_only': True, 'max_length': 8, 'min_length': 3}
        }
  
  # 重写字段
  # 局部和全局钩子跟之前一样,但是要注意写在Meta外

四、序列化多表操作

1、代码

 多表模型

from django.db import models


class Book(models.Model):
    name = models.CharField(max_length=32, )
    price = models.DecimalField(max_digits=8, decimal_places=2)
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return self.name

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

    @property
    def author_list(self):
        l = []
        for author in self.authors.all():
            l.append({'name': author.name, 'addr': author.author_detail.addr})
        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)


class AuthorDetail(models.Model):
    phone = models.BigIntegerField()
    birthday = models.DateTimeField()
    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(max_length=32, )

序列化器

from app01 import models
from rest_framework.serializers import ModelSerializer


class BookSerializer(ModelSerializer):
    class Meta:
        model = models.Book
        # fields = '__all__'
        # depth = 1
        fields = ['id', 'name', 'price', 'publish', 'authors', 'publish_detail', 'author_list']

        extra_kwargs = {
            'publish': {'write_only': True},
            'authors': {'write_only': True}
        }


class AuthorSerializer(ModelSerializer):
    class Meta:
        model = models.Author
        fields = '__all__'


class AuthorDetailSerializer(ModelSerializer):
    class Meta:
        models = models.AuthorDetail
        fields = '__all__'


class PublishSerializer(ModelSerializer):
    class Meta():
        model = models.Publish
        fields = '__all__'                  

视图接口

from rest_framework.response import Response
from rest_framework.views import APIView
from app01 import models
from app01 import serializer


class BookView(APIView):
    def get(self, request):
        book_list = models.Book.objects.all()
        ser = serializer.BookSerializer(instance=book_list, many=True)
        return Response(ser.data)

    def post(self, request):
        ser = serializer.BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({"code": 100, "msg": "新增成功", "data": ser.data})
        return Response({"code": 101, "msg": "新增失败", "err": ser.errors})


class BookDetailView(APIView):
    def get(self, request, pk):
        book = models.Book.objects.all().filter(pk=pk).first()
        ser = serializer.BookSerializer(instance=book)
        return Response(ser.data)

    def put(self, request, pk):
        book = models.Book.objects.all().filter(pk=pk).first()
        ser = serializer.BookSerializer(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({"code": 100, "msg": "修改成功", "data": request.data})
        return Response({"code": 102, "msg": "修改失败", "err": ser.errors})

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

路由

from django.contrib import admin
from django.urls import path
from app01 import views

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

2、验证

查看所有

 

 

添加一个

查看一个

 

 

修改一个

删除一个

五、请求和响应

 这里的请求和响应是经过drf封装之后的请求和响应,增加了一些内容

请求

# Request 类的对象---》新的request对象
from rest_framework.request import Request
# 记住的
    __getattr__
    request.data
  request.query_parmas--->self._request.GET-->restful规范里,请求地址中带过滤(查询)条件---》get请求地址中提交的数据在GET中,---》query_parmas:查询参数
  

# 了解--->默认情况下,可以解析 urlencoded,formdata,json
    -如果我们写了一个接口,想只能处理json格式,或者只能处理formdata
    
  
  
# 局部配置
from rest_framework.parsers import JSONParser,FormParser,MultiPartParser
class PublishView(APIView):
    # 局部使用,只针对当前视图类有效,只想处理json格式
    parser_classes = [JSONParser]

# 全局配置---》配置文件--->所有接口都只能解析json格式
REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
    ],
}

# 全局配置解析json,局部某个视图函数想能解析formdata格式

视图类中配置一下即可---》局部配置

-如果局部配置如下,会怎么样
parser_classes = [] # 所有格式都补不能解析了

# 使用顺序:我们没有配置,也有默认配置:3个都能解析
    drf有默认配置(最后)----》项目配置文件的配置(其次)----》视图类中配的(优先用)
  drf的默认配置:from rest_framework import settings
  
  
  
  
 # 总结:一般情况下,都使用默认即可,不用配置
View Code

响应

Respone:from rest_framework.response import Response

# 属性
data=None,    # 字符串,字典,列表--》给http响应body体中内容-->response对象中取出处理
status=None,  # 响应状态码:1xx,2xx,3xx,默认是200
from rest_framework.status import HTTP_201_CREATED
Response(ser.data,status=HTTP_201_CREATED)

headers=None,      # 响应头 字典
  
---了解---
template_name=None,  # 模板名字(不用),用浏览器访问时,可以改
exception=False,    # 异常处理
content_type=None   # 响应编码格式



# 响应格式---》跟解析格式

# 局部设置
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
class BookDetailView(APIView):
    renderer_classes = [JSONRenderer,]
# 全局设置
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
        'rest_framework.renderers.JSONRenderer',  # json渲染器
        'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览API渲染器
    )
}
View Code

 

 

这篇关于12_03、drf之序列化和反序列化的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!