drf03 序列化器
一、序列化器-Serializer
作用:
1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
2. 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
3. 反序列化,完成数据校验功能
1. 定义序列化器
1.1 创建项目
python manage.py startapp app02_serializer
1.2 构建模型
from django.db import models
# Create your models here.
class BookAPIView(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5, decimal_places=2)
author = models.CharField(max_length=32)
publish = models.CharField(max_length=32)
1.3 根据模型定义一个序列化器
from rest_framework import serializers
# 声明序列化器,所有的序列化器都要直接或者间接继承于 Serializer
# 其中,ModelSerializer是Serializer的子类,ModelSerializer在Serializer的基础上进行了代码简化
class BookSerializer(serializers.Serializer):
# 1. 需要进行数据转换的字段
id = serializers.IntegerField(read_only=True, write_only=False)
name = serializers.CharField(max_length=32)
price = serializers.DecimalField(max_digits=5, decimal_places=2)
author = serializers.CharField(max_length=32)
publish = serializers.CharField(max_length=32)
# 2. 如果序列化器集成的是ModelSerializer,则需要声明调用的模型信息
# 3. 验证代码
# 4. 编写添加和更新模型的代码
注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。serializer是独立于数据库之外的存在。
1.4 总结 - 参数
定义字段类型可以都用CharField,后续根据字段类型再去处理
常用参数
many # 默认为False 多条数据要设置为 many=True
max_length、min_length
read_only、write_only、 # 这两个默认为False ,针对特定字段赋予权限
required、 # 表示在反序列化时,需要输入数据
validators、 # 该字段使用的验证器
label # 取别名 和model类似
source 对象的字段、跨表字段 、[函数内存地址] # 高级用法
(1) 常用字段类型:
| 字段 | 字段构造方式 |
|---|---|
| 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=) |
(2) 选项参数:
| 参数名称 | 作用 |
|---|---|
| max_length | 最大长度 |
| min_length | 最小长度 |
| allow_blank | 是否允许为空 |
| trim_whitespace | 是否截断空白字符 |
| max_value | 最大值 |
| min_value | 最小值 |
(3) 通用参数:
| 参数名称 | 说明 |
|---|---|
| read_only | 表明该字段仅用于序列化输出,默认False |
| write_only | 表明该字段仅用于反序列化输入,默认False |
| required | 表明该字段在反序列化时必须输入,默认True |
| default | 反序列化时使用的默认值 |
| allow_null | 表明该字段是否允许传入None,默认False |
| validators | 该字段使用的验证器 |
| error_messages | 包含错误编号与错误信息的字典 |
| label | 用于HTML展示API页面时,显示的字段名称 |
| help_text | 用于HTML展示API页面时,显示的字段帮助提示信息 |
2. 创建序列化对象
定义好Serializer类后,就可以创建Serializer对象了。
Serializer的构造方法为:
BookSerializer(instance=None, data=empty, **kwarg)
说明:
1)用于序列化时,将模型类对象传入instance参数
2)用于反序列化时,将要被反序列化的数据传入data参数
3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如
book_ser = BookSerializer(account, context={'request': request})
通过context参数附加的数据,可以通过Serializer对象的context属性获取。
- 使用序列化器的时候一定要注意,序列化器声明了以后,不会自动执行,需要我们在视图中进行调用才可以。
- 序列化器无法直接接收数据,需要我们在视图中创建序列化器对象时把使用的数据传递过来。
- 序列化器的字段声明类似于我们前面使用过的表单系统。
- 开发restful api时,序列化器会帮我们把模型数据转换成字典.
- drf提供的视图会帮我们把字典转换成json,或者把客户端发送过来的数据转换字典.
3. 序列化器的使用
序列化器的使用分两个阶段:
- 在客户端请求时,使用序列化器可以完成对数据的反序列化。
- 在服务器响应时,使用序列化器可以完成对数据的序列化。
3.1序列化
使用序列化器进行序列化的时候,只需要传入instance-对象即可,并且只需要调用data 方法就能获取序列化以后的结果
book_queryset = models.BookAPIView.objects.all()
book_ser = BookModelSerializer(instance=book_queryset, many=True)
book_ser.data
3.2 反序列化
3.2.1 数据验证
(1) is_valid 验证是否成功
-
使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
-
在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。
-
验证成功,需要调用序列化对象的save()保存数据,不调用这个方法不能真正的保存,当然保存可能牵涉到create、update方法的重写,可以参考modelserializer,然后通过序列化器对象的validated_data属性获取数据
-
验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
book_obj = models.BookAPIView.objects.filter(pk=pk)
book_ser = BookSerializer(instance=book_obj, data=request.data)
if book_ser.is_valid():
book_ser.save()
book_ser.data
else:
book_ser.errors
(2) validators 在字段中自己定义
from rest_framework import serializers
from app02_serializer import models
from rest_framework.exceptions import ValidationError
# 可用于局部过滤
def clean_name(data):
if len(data) > 3:
raise ValidationError('名字太长了')
else:
return data
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, write_only=False)
name = serializers.CharField(max_length=32,validators=[clean_name]) # validators=[] 列表中写函数内存地址
price = serializers.DecimalField(max_digits=5, decimal_places=2)
author = serializers.CharField(max_length=32)
publish = serializers.CharField(max_length=32)
(3) validate 钩子函数
from rest_framework import serializers
from app02_serializer import models
from rest_framework.exceptions import ValidationError
# 局部钩子 - validate_字段名 data 是 price字段
def validate_price(self, data):
if data > 10:
pass
else:
raise ValidationError('价格太低了')
return data
# 全局钩子 - validate data 是所有数据
def validate(self, data):
name = data.get('name')
author = data.get('author')
if name == author:
pass
else:
raise ValidationError('作者和书名不一致')
return data
3.2.2 数据保存
前面的验证数据成功后,我们可以使用序列化器来完成数据反序列化的过程.这个过程可以把数据转成模型类对象
自己定义了一个响应类,用来储存信息
响应消息类
class MyResponse(object):
def __int__(self):
# 定制化响应内容
self.status = 200
self.msg = "请求成功"
self.data = ""
@property
def get_dict(self):
if self.__dict__:
return self.__dict__
if __name__ == '__main__':
a = MyResponse()
a.status = 202
# a.msg = '请求成功'
# a.data = '数据'
print(a.get_dict)
配置路由
# 为以下方法配置路由 - get-all post
path('books/', views.BooksView.as_view()),
# 为以下方法配置路由 - get/put/delete - pk
re_path(r'^books/(?P<pk>\d+)/', views.BookView.as_view()),
(1)get方法 - pk
from rest_framework.views import APIView
from app02_serializer import models
from app02_serializer.myserializer.ser01 import BookSerializer
from rest_framework.response import Response
from app02_serializer.utils.reponseUtil import MyResponse
class BookView(APIView):
# get 方法获取单条或多条数据
def get(self, request, pk):
print('get-pk方法')
response_msg = MyResponse()
# 根据pk获取
# 用一个类,毫无疑问,一定要实例化
# 要序列化谁,就把谁传过来
book_obj = models.BookAPIView.objects.filter(id=pk).first() # # 调用类的__init__
# book_ser.data 序列化对象.data就是序列化后的字典
book_ser = BookSerializer(instance=book_obj) # 如果不加 many = True 则只能返回一个对象
response_msg.status = 200
response_msg.msg = '请求成功'
response_msg.data = book_ser.data
return Response(response_msg.get_dict)
(2) get方法 - all
from rest_framework.views import APIView
from app02_serializer import models
from app02_serializer.myserializer.ser01 import BookSerializer
from rest_framework.response import Response
from app02_serializer.utils.reponseUtil import MyResponse
class BooksView(APIView):
# get 方法获取单条或多条数据
def get(self, request):
print('get-all方法')
response_msg = MyResponse()
# 获取全部数据
book_queryset = models.BookAPIView.objects.all()
book_ser = BookSerializer(instance=book_queryset, many=True) # 序列化多条,如果序列化一条,不需要写
response_msg.status = 200
response_msg.msg = '请求成功'
response_msg.data = book_ser.data
return Response(response_msg.get_dict)
(3) post方法 - 需重写create方法
from rest_framework.views import APIView
from app02_serializer import models
from app02_serializer.myserializer.ser01 import BookSerializer
from rest_framework.response import Response
from app02_serializer.utils.reponseUtil import MyResponse
class BooksView(APIView):
# post 创建数据
def post(self, request):
print('post方法')
response_msg = MyResponse()
# 修改才有instance,新增没有instance,只有data
book_ser = BookSerializer(data=request.data)
if book_ser.is_valid():
book_ser.save()
response_msg.status = 200
response_msg.msg = '创建成功'
response_msg.data = book_ser.data
else:
response_msg.status = 201
response_msg.msg = '创建失败'
response_msg.data = book_ser.errors
return Response(response_msg.get_dict)
(4) put方法 - 需重写update方法
from rest_framework.views import APIView
from app02_serializer import models
from app02_serializer.myserializer.ser01 import BookSerializer
from rest_framework.response import Response
from app02_serializer.utils.reponseUtil import MyResponse
class BookView(APIView):
# put 方法更新数据,全局更新
def put(self, request, pk):
print('put方法')
# 根据pk修改
response_msg = MyResponse()
# 找到这个对象
book_obj = models.BookAPIView.objects.filter(pk=pk)
# 得到一个序列化类的对象
# boo_ser=BookSerializer(book,request.data)
book_ser = BookSerializer(instance=book_obj, data=request.data)
if book_ser.is_valid():
book_ser.save()
response_msg.status = 200
response_msg.msg = '更新成功'
response_msg.data = book_ser.data
else:
response_msg.status = 201
response_msg.msg = '更新失败'
response_msg.data = book_ser.errors
return Response(response_msg.get_dict)
(5) delete方法
from rest_framework.views import APIView
from app02_serializer import models
from app02_serializer.myserializer.ser01 import BookSerializer
from rest_framework.response import Response
from app02_serializer.utils.reponseUtil import MyResponse
class BookView(APIView):
def delete(self, request, pk):
print('delete方法')
response_msg = MyResponse()
book_obj = models.BookAPIView.objects.filter(pk=pk).delete()
book_res = BookSerializer(data=request.data)
book_res.is_valid()
if book_obj:
response_msg.status = 200
response_msg.msg = '删除成功'
response_msg.data = book_res.data
else:
response_msg.status = 201
response_msg.msg = '删除失败'
response_msg.data = book_res.errors
return Response(response_msg.get_dict)
3.2.3 附加说明
(1) create( )方法
当使用post方法保存数据的时候,需要在自定义的序列化器中重写create方法用来保存数据
from rest_framework import serializers
from app02_serializer import models
from rest_framework.exceptions import ValidationError
class BookSerializer(serializers.Serializer):
# post方法 要重写create 方法
def create(self, validated_data):
# 获取一个类 Book
instance = models.BookAPIView.objects.create(**validated_data)
return instance
(2) update() 方法
from rest_framework import serializers
from app02_serializer import models
from rest_framework.exceptions import ValidationError
class BookSerializer(serializers.Serializer):
# put 方法 要重写update
def update(self, instance, validated_data):
instance = models.BookAPIView.objects.create(**validated_data)
# instance = models.Book.objects.create(name=validated_data.get('name'))
return instance
3.3 序列化器之高级用法-source方法
source方法主要用来指定字段 或者跨表字段 + SerializerMethodField + 自定义方法
3.3.1 models.py
from django.db import model
# 关系备注:book - publish 一对多
# 关系备注:book - author 多对多
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.IntegerField()
pub_date = models.DateField()
publish = models.ForeignKey("Publish", on_delete=models.CASCADE, null=True)
authors = models.ManyToManyField("Author")
def __str__(self):
return self.title
def test(data):
import datetime
return '{}'.format(datetime.datetime.now())
class Publish(models.Model):
name = models.CharField(max_length=32)
email = models.EmailField()
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
def __str__(self):
return self.name
3.3.2 ser.py
-
source 方法只能是models.py 中 且 是与 该表对象 是有关联的
-
用source 可以用来表示这个序列化对象的字段名 + 函数 + 跨表字段
from rest_framework import serializers
class BookManySerializer(serializers.Serializer):
# book.publish
# book.price
# book.xxx--->book.title
# book.authors.all
xxx=serializers.CharField(source='title') # 字段名
price=serializers.CharField()
pub_date=serializers.CharField(source='test') # 对应方法
publish=serializers.CharField(source='publish.email') # 一对一关系
authors=serializers.SerializerMethodField() # 多对多关系
#它需要有个配套方法,方法名叫get_字段名,返回值就是要显示的东西
def get_authors(self,instance):
# book对象
authors=instance.authors.all() # 取出所有作者
ll=[]
for author in authors:
ll.append({'name':author.name,'age':author.age})
return ll
3.3.3 urls.py
# manymodelserializer
re_path(r'^books_manymodel/(?P<pk>\d+)/', views.BookManyModelView.as_view()),
3.3.4 views.py
from rest_framework.views import APIView
from app02_serializer import models
from app02_serializer.myserializer.ser02 import BookManySerializer
from rest_framework.response import Response
class BookManyModelView(APIView):
def get(self, request, pk):
book_obj = models.Book.objects.filter(id=pk).first()
book_ser = BookManySerializer(book_obj)
return Response(book_ser.data)
4.模型序列化器
如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。
ModelSerializer与常规的Serializer相同,但提供了:
- 基于模型类自动生成一系列字段
- 基于模型类自动为Serializer生成validators,比如unique_together
- 包含默认的create()和update()的实现
4.1 定义
from rest_framework import serializers
from app02_serializer import models
from rest_framework.exceptions import ValidationError
class BookModelSerializer(serializers.ModelSerializer):
# 如果模型类序列化器,必须声明本次调用是哪个模型,模型里面的哪些字段
class Meta:
model = models.BookAPIView
# 全部字段
fields = '__all__' # 所有字段
# 选择字段
# fields = ['name','price','author']
# 排除字段
# exclude = ['id'] # 去除id
# 额外字段
extra_kwargs = {
'id': {'read_only': True}
}
# 注意:
# fields 和 exclude 只能选择一个
# 字段必须是该模型中的字段
4.2 指定字段
指定字段有两种方式 :
fields
exclude
# fields
# 全部
fields = '__all__' # 所有字段
# 选择部分字段
fields = ['name','price','author']
# exclude
exclude = ['id'] # 去除id
4.3 额外参数
我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数
# 这参数的话,其实是跟序列化器的用法是一样的但是写法不同而已
# 两者写法对比
# 序列化器
id = serializers.IntegerField(read_only=True, write_only=False)
# 模型序列化器
extra_kwargs = {
'id': {'read_only': True,'write_only':False}
}
4.4 使用
from rest_framework.views import APIView
from app02_serializer import models
from app02_serializer.myserializer.ser02 import BookManySerializer
from rest_framework.response import Response
class BookManyModelView(APIView):
def get(self, request, pk):
book_obj = models.Book.objects.filter(id=pk).first()
book_ser = BookManySerializer(book_obj)
return Response(book_ser.data)

浙公网安备 33010602011771号