序列化器-Serializer
目录
序列化器-Serializer
作用:
- 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
- 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
- 反序列化,完成数据校验功能
#先在models.py中写创建表
from django.db import models
class Book(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8, decimal_places=3)
author = models.CharField(max_length=32)
publish = models.CharField(max_length=32)
1、序列化器使用
写一个序列化类,继承Serializer
在类中写要序列化的字段,想要序列化哪个字段,就在类中写哪个字段
在视图类中使用,导入自己写的序列化类(ser.py)---》实例化得到序列化类的对象,把要序列化的对象传入
序列化类的对象.data 是一个字典
把字典返回,如果不使用rest_framework提供的Resposne,就得使用JsonResponse
# 自己创建的ser.py文件中写序列化类
from rest_framework import serializers
# 需要继承Serializer
class BookSeralizer(serializers.Serializer):
#想要序列化哪个字段,就在类中写哪个字段
id = serializers.CharField()
name = serializers.CharField()
price = serializers.CharField()
author = serializers.CharField()
publish = serializers.CharField()
#urls.py
re_path('books/(?P<pk>\d+)', views.BookView.as_view())
#views.py
from rest_framework.views import APIView
from App.models import Book
from App.ser import BookSeralizer
from rest_framework.response import Response # drf提供的响应对象
class BookView(APIView):
def get(self, request, pk):
book_obj = Book.objects.filter(pk=pk).first()
# 序列化谁,就把谁传过来
book_ser = BookSeralizer(book_obj) # 调用类的__init__方法
# 序列化对象.data就是序列化后的字典
return Response(book_ser.data)
如果使用JsonResponse
返回数据,效果如下:
如果使用JsonResponse
返回数据,就不需要在settings.py
中注册rest_framework
了
注意:
如果碰到下面的报错,需要把rest_framework
在settings.py中的app中注册
2、序列化类的字段类型
有很多,
只需记住 CharField IntegerField,DateField......
字段类型:
选项参数:
通用参数:
3、序列化组件修改保存数据
1.写一个序列化类,继承Serializer
2.在类中写要反序列化的字段,想要反序列化哪个字段,就在类中写哪个字段,字段的属性(max_length.....)
3.在视图类中使用,导入---》实例化得到序列化类的对象,把要修改的数据传入
book_ser = BookSeralizer(book_obj, request.data)
book_ser = BookSeralizer(instance=book_obj, data=request.data)
#自己创建的ser.py文件
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
# 需要继承Serializer
class BookSeralizer(serializers.Serializer):
name = serializers.CharField(max_length=16, min_length=4)
price = serializers.CharField()
author = serializers.CharField()
publish = serializers.CharField()
def update(self, instance, validated_data):
# instance是Book这个对象
# validated_data是校验后的数据
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
instance.author = validated_data.get("author")
instance.publish = validated_data.get('publish')
instance.save() # book.save() 是django 的orm提供的
return instance
#urls.py
re_path('books/(?P<pk>\d+)', views.BookView.as_view())
#views.py
from rest_framework.views import APIView
from App.models import Book
from App.ser import BookSeralizer
from rest_framework.response import Response # drf提供的响应对象
class BookView(APIView):
def put(self, request, pk):
response_msg = {'code': 100, 'msg': ''}
# 找到要改的对象
book_obj = Book.objects.filter(pk=pk).first()
# 得到序列化类的对象
# book_ser = BookSeralizer(book_obj, request.data)
book_ser = BookSeralizer(instance=book_obj, data=request.data)
# 要验证(和forms组件校验一样)
if book_ser.is_valid(): # 表示验证通过
book_ser.save()
response_msg['msg'] = '数据校验成功'
response_msg['data'] = book_ser.data
else:
response_msg['code'] = 101
response_msg['msg'] = '数据校验失败'
response_msg['data'] = book_ser.errors
return Response(response_msg)
4、序列化组件校验数据
1.写一个序列化类,继承Serializer
2.在类中写要反序列化的字段,想要反序列化哪个字段,就在类中写哪个字段,字段的属性(max_length.....)
3.在视图类中使用,导入---》实例化得到序列化类的对象,把要修改的数据传入
book_ser = BookSeralizer(book_obj, request.data)
book_ser = BookSeralizer(instance=book_obj, data=request.data)
4.数据校验 if book_ser.is_valid()
5.如果校验通过就保存,视图中调用 序列化对象 ook_ser.save() 序列化对象.save()
6.如果不通过,逻辑自己写
7.如果字段的校验规则不够,可以写钩子函数(局部和全局)
# 局部钩子
def validate_price(self, data): # validate_字段名,接受一个参数
# print(type(data))
# print(data)
if float(data) < 10:
# 校验失败,抛异常
raise ValidationError('价格太低')
return data
# 全局钩子
def validate(self, validated_data):
author = validated_data.get("author")
publish = validated_data.get("publish")
if author == publish:
raise ValidationError("作者跟出版社一样")
return validated_data
8. 可以使用字段的validators来校验
author = serializers.CharField(validators=[check_author]), 来校验
-写一个函数
def check_author(data):
if data.startswith('sb'):
raise ValidationError('作者名不能以sb开头')
-配置:author =validators=[check_author]
re_path('books/(?P<pk>\d+)', views.BookView.as_view())
局部(全局)钩子校验:
#自己创建的ser.py文件
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
# 需要继承Serializer
class BookSeralizer(serializers.Serializer):
name = serializers.CharField(max_length=16, min_length=4)
price = serializers.CharField()
author = serializers.CharField()
publish = serializers.CharField()
# 局部钩子
def validate_price(self, data): # validate_字段名,接受一个参数
# print(type(data))
# print(data)
# 如果价格小于10,校验不通过
if float(data) < 10:
# 校验失败,抛异常
raise ValidationError('价格太低')
return data
# 全局钩子
def validate(self, validated_data):
author = validated_data.get("author")
publish = validated_data.get("publish")
if author == publish:
raise ValidationError("作者跟出版社一样")
return validated_data
def update(self, instance, validated_data):
# instance是Book这个对象
# validated_data是校验后的数据
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
instance.author = validated_data.get("author")
instance.publish = validated_data.get('publish')
instance.save() # book.save() 是django 的orm提供的
return instance
自己逻辑上的校验:
#views.py
from rest_framework.views import APIView
from App.models import Book
from App.ser import BookSeralizer
from rest_framework.response import Response # drf提供的响应对象
class BookView(APIView):
def put(self, request, pk):
response_msg = {'code': 100, 'msg': ''}
# 找到要改的对象
book_obj = Book.objects.filter(pk=pk).first()
# 得到序列化类的对象
# book_ser = BookSeralizer(book_obj, request.data)
book_ser = BookSeralizer(instance=book_obj, data=request.data)
# 要验证(和forms组件校验一样)
if book_ser.is_valid(): # 表示验证通过
book_ser.save()
response_msg['msg'] = '数据校验成功'
response_msg['data'] = book_ser.data
else:
response_msg['code'] = 101
response_msg['msg'] = '数据校验失败'
response_msg['data'] = book_ser.errors
return Response(response_msg)
校验:
def check_author(data):
if data.startswith('sb'):
raise ValidationError('作者名不能以sb开头')
# 需要继承Serializer
class BookSeralizer(serializers.Serializer):
name = serializers.CharField(max_length=16, min_length=4)
price = serializers.CharField()
author = serializers.CharField(validators=[check_author]) # validators=[],列表中写函数内存地址
publish = serializers.CharField()
全部代码:
- 1 表模型类
#models.py
from django.db import models
class Book(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8, decimal_places=3)
author = models.CharField(max_length=32)
publish = models.CharField(max_length=32)
- 2 序列化类
# -*- coding: UTF-8 -*-
# @Date :2022/12/2 15:29
#ser.py
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
def check_author(data):
if data.startswith('sb'):
raise ValidationError('作者名不能以sb开头')
# 需要继承Serializer
class BookSeralizer(serializers.Serializer):
name = serializers.CharField(max_length=16, min_length=4)
price = serializers.CharField()
author = serializers.CharField(validators=[check_author]) # validators=[],列表中写函数内存地址
publish = serializers.CharField()
# 局部钩子
def validate_price(self, data): # validate_字段名,接受一个参数
# print(type(data))
# print(data)
# 如果价格小于10,校验不通过
if float(data) < 10:
# 校验失败,抛异常
raise ValidationError('价格太低')
return data
def validate(self, validated_data): # 全局钩子
author = validated_data.get("author")
publish = validated_data.get("publish")
if author == publish:
raise ValidationError("作者跟出版社一样")
return validated_data
def update(self, instance, validated_data):
# instance是Book这个对象
# validated_data是校验后的数据
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
instance.author = validated_data.get("author")
instance.publish = validated_data.get('publish')
instance.save() # book.save() 是django 的orm提供的
return instance
- 3 路由配置
#urls.py
from django.contrib import admin
from django.urls import path, re_path
from App import views
urlpatterns = [
path('admin/', admin.site.urls),
re_path('books/(?P<pk>\d+)', views.BookView.as_view())
]
- 4 书写视图类
#views.py
from django.shortcuts import render
from rest_framework.views import APIView
from App.models import Book
from App.ser import BookSeralizer
from rest_framework.response import Response # drf提供的响应对象
from django.http import JsonResponse
class BookView(APIView):
def get(self, request, pk):
book_obj = Book.objects.filter(pk=pk).first()
# 序列化谁,就把谁传过来
book_ser = BookSeralizer(book_obj) # 调用类的__init__方法
# 序列化对象.data就是序列化后的字典
return Response(book_ser.data)
# return JsonResponse(book_ser.data)
def put(self, request, pk):
response_msg = {'code': 100, 'msg': ''}
# 找到要改的对象
book_obj = Book.objects.filter(pk=pk).first()
# 得到序列化类的对象
# book_ser = BookSeralizer(book_obj, request.data)
book_ser = BookSeralizer(instance=book_obj, data=request.data)
# 要验证(和forms组件校验一样)
if book_ser.is_valid(): # 表示验证通过
book_ser.save()
response_msg['msg'] = '数据校验成功'
response_msg['data'] = book_ser.data
else:
response_msg['code'] = 101
response_msg['msg'] = '数据校验失败'
response_msg['data'] = book_ser.errors
return Response(response_msg)
4、reand_only和write_only
- read_only
表明该字段仅仅用于序列化输出,默认False,
如果设置成True,postman中可以看到该字段,修改时不需要传该字段
- write_only
表明该字段仅仅用户反序列化输入,默认False,
如果设置成了True,postman看不到该字段,但修改时,该字段必须传
5、查看所有,删除,新增
- 查询所有数据
path('books/', views.BooksView.as_view())
#views.py
重新写一个视图类
class BooksView(APIView):
def get(self, request):
response_msg = {'code': 100, 'msg': ''}
books_obj = Book.objects.all()
book_ser = BookSeralizer(books_obj, many=True) # 序列化多条,如果序列化一条,不需要写
response_msg['data'] = book_ser.data
response_msg['msg'] = '校验成功'
return Response(response_msg)
- 新增数据
# urls.py
path('books/', views.BooksView.as_view())
#views.py
class BooksView(APIView):
# 新增数据
def post(self, request):
response_msg = {'code': 100, 'msg': '校验成功'}
# 修改才有instance,新增没有,只有data
book_ser = BookSeralizer(data=request.data)
# book_ser = BookSeralizer(request.data) #按位置传参数request.data,会给instance,就报错了
# 校验数据
if book_ser.is_valid():
book_ser.save()
response_msg['data'] = book_ser.data
else:
response_msg['code'] = 102
response_msg['msg'] = '数据校验失败'
response_msg['data'] = book_ser.errors
return Response(response_msg)
#ser.py
#在序列化类中重写create方法
def create(self, validated_data):
# Book.objects.create(name=validated_data.get('name'))
instance = Book.objects.create(**validated_data)
return instance
- 删除数据
#urls.py
re_path('books/(?P<pk>\d+)', views.BookView.as_view()),
#views.py
class BookView(APIView):
def delete(self, request, pk):
book_obj = Book.objects.filter(pk=pk).delete()
response_msg = {'code': 100, 'msg': '删除成功'}
return Response(response_msg)
6、自定义Response对象
# -*- coding: UTF-8 -*-
# @Date :2022/12/2 19:30
#创建一个utils.py文件
class MyResponse():
def __init__(self):
self.code = 100
self.msg = '成功'
@property
def get_dict(self):
return self.__dict__
代码:
- models.py
from django.db import models
# Create your models here.
class Book(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8, decimal_places=3)
author = models.CharField(max_length=32)
publish = models.CharField(max_length=32)
- 序列化类
# -*- coding: UTF-8 -*-
# @Date :2022/12/2 19:53
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from App.models import Book
def check_author(data):
if data.startswith('sb'):
raise ValidationError('作者不能以sb开头')
class BookSerializer(serializers.Serializer):
id = serializers.CharField(read_only=True)
name = serializers.CharField(max_length=16, min_length=4)
price = serializers.CharField(write_only=True)
author = serializers.CharField(validators=[check_author])
publish = serializers.CharField()
def validate_price(self, data):
if float(data) < 10:
raise ValidationError('价格太低了')
return data
def validate(self, validate_data):
author = validate_data.get('author')
publish = validate_data.get('publish')
if author == publish:
raise ValidationError('作者和出版社一样')
return validate_data
def update(self, instance, validated_data):
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
instance.author = validated_data.get('author')
instance.publish = validated_data.get('publish')
instance.save()
return instance
def create(self, validated_data):
instance = Book.objects.create(**validated_data)
return instance
- 自定义Response
# -*- coding: UTF-8 -*-
# @Date :2022/12/2 20:12
class MyResponse:
def __init__(self):
self.code = 100
self.msg = '检验成功'
@property
def get_dict(self):
return self.__dict__
if __name__ == '__main__':
res = MyResponse()
res.data = {'name': 'zhao'}
print(res.get_dict)
- urls.py
from django.contrib import admin
from django.urls import path, re_path
from App import views
urlpatterns = [
path('admin/', admin.site.urls),
re_path('book/(?P<pk>\d+)',views.BookView.as_view()),
path('books/',views.BooksView.as_view())
]
- 视图类的书写
from django.shortcuts import render
from rest_framework.views import APIView
from App.models import Book
from App.ser import BookSerializer
from rest_framework.response import Response
from App.utils import MyResponse
# Create your views here.
class BookView(APIView):
# 获取单个数据
def get(self, request, pk):
book_obj = Book.objects.filter(pk=pk).first()
book_ser = BookSerializer(book_obj)
return Response(book_ser.data)
# 修改数据
def put(self, request, pk):
response = MyResponse()
book_obj = Book.objects.filter(pk=pk).first()
book_er = BookSerializer(instance=book_obj, data=request.data)
if book_er.is_valid():
book_er.save()
response.data = book_er.data
response.msg = '校验成功'
else:
response.msg = '校验失败'
response.code = 101
response.data = book_er.errors
return Response(response.get_dict)
# 删除数据
def delete(self, request, pk):
response = MyResponse()
Book.objects.filter(pk=pk).delete()
return Response(response.get_dict)
class BooksView(APIView):
# 获取所有数据
def get(self, request):
response = MyResponse()
books_obj = Book.objects.all()
book_er = BookSerializer(books_obj, many=True)
response.data = book_er.data
return Response(response.get_dict)
# 新增数据
def post(self, request):
response = MyResponse()
book_ser = BookSerializer(data=request.data)
if book_ser.is_valid():
book_ser.save()
response.data = book_ser.data
else:
response.data = book_ser.errors
response.msg = '校验失败'
response.code = 101
return Response(response.get_dict)
7、模型类的序列化器
#ser.py 序列化类
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = Book # 对应models.py中的模型
fields = '__all__' # 表示所有字段都序列化
# fields = ('name', 'price') # 序列化指定字段
# exclude = ('name',) # 除了name字段,其他都序列化
# 给authors和publish加write_only属性
# name加max_len属性
extra_kwargs = {
'name': {'max_length': 8},
'publish': {'write_only': True},
'authors': {'write_only': True},
}
#urls.py
path('books2/', views.BooksView2.as_view())
#views.py
from App.ser import BookModelSerializer
class BooksView2(APIView):
def get(self, request):
response = MyResponse()
book_obj = Book.objects.all()
book_ser = BookModelSerializer(book_obj, many=True)
response.data = book_ser.data
return Response(response.get_dict)
8、关键字many源码分析
# 序列化多条,需要传many=True
path('many/',views.ManyView.as_view()),
class ManyView(APIView):
def get(self, request):
response = MyResponse()
book_obj = Book.objects.filter().first()
books_obj = Book.objects.all()
book_ser = BookModelSerializer(book_obj)#序列化单条
books_ser = BookModelSerializer(books_obj, many=True)#序列化多条
print(type(book_ser)) # <class 'App.ser.BookModelSerializer'>
print(type(books_ser))
# <class 'rest_framework.serializers.ListSerializer'>
response.data = books_ser.data
return Response(response.get_dict)
#对象的生成---》先调用类的__new__方法,生成空对象
#对象=类名(name=zhao),触发类的__init__()
#类的__new__方法控制对象的生成
"""源码分析"""
class BaseSerializer(Field):
def __new__(cls, *args, **kwargs):
if kwargs.pop('many', False):
return cls.many_init(*args, **kwargs)
#没有传many=True,走下面,正常的对象实例化,
return super().__new__(cls, *args, **kwargs)
@classmethod
def many_init(cls, *args, **kwargs):
allow_empty = kwargs.pop('allow_empty', None)
max_length = kwargs.pop('max_length', None)
min_length = kwargs.pop('min_length', None)
child_serializer = cls(*args, **kwargs)
list_kwargs = {
'child': child_serializer,
}
if allow_empty is not None:
list_kwargs['allow_empty'] = allow_empty
if max_length is not None:
list_kwargs['max_length'] = max_length
if min_length is not None:
list_kwargs['min_length'] = min_length
list_kwargs.update({
key: value for key, value in kwargs.items()
if key in LIST_SERIALIZER_KWARGS
})
meta = getattr(cls, 'Meta', None)
list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer)
return list_serializer_class(*args, **list_kwargs)
9、Serializer高级用法
新创建一个应用,记得一定要去注册!
# 路由分发
from App2 import urls
# path('App2/', include('App2.urls'))
path('App2/', include(urls)),
#App2.等models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.IntegerField()
pub_date = models.DateTimeField()
publish = models.ForeignKey('Publish', on_delete=models.CASCADE, null=True)
authors = models.ManyToManyField('Author')
def __str__(self):
return self.title
class Publish(models.Model):
name = models.CharField(max_length=32)
email = models.EmailField()
def __str__(self):
return self.name
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
def __str__(self):
return self.name
#App2.views.py
from django.shortcuts import render
from App2.models import Book
from App2.ser import BookSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
class App2BookView(APIView):
def get(self, request, pk):
book_obj = Book.objects.filter(pk=pk).first()
book_ser = BookSerializer(book_obj)
return Response(book_ser.data)
# -*- coding: UTF-8 -*-
# @Date :2022/12/3 16:27
#App2.ser.py
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
title123 = serializers.CharField(source='title')
price = serializers.CharField()
authors = serializers.CharField()
publish = serializers.CharField(source='publish.email') # 相当于book.publish.email
pub_date = serializers.CharField()
# -*- coding: UTF-8 -*-
# @Date :2022/12/3 16:27
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
title123 = serializers.CharField(source='title')
price = serializers.CharField()
# authors = serializers.CharField()
authors = serializers.SerializerMethodField() # 必须配一个方法,方法名叫get_字段名,返回值就是要显示的内容
def get_authors(self, instance):
# book对象
authors = instance.authors.all() # 取出所有作者
l = []
for author in authors:
l.append({'name': author.name, 'age': author.age})
return l
publish = serializers.CharField(source='publish.email') # 相当于book.publish.email
pub_date = serializers.CharField()
source
# 可以改字段名字
title123 = serializers.CharField(source='title')
# 可以.跨表
publish = serializers.CharField(source='publish.email') # 相当于book.publish.email
# 可以执行方法
pub_date = serializers.CharField(source='test') # test是Book表模型中
SerializerMethodField()
authors = serializers.SerializerMethodField() # 必须配一个方法,方法名叫get_字段名,返回值就是要显示的内容
def get_authors(self, instance):
# book对象
authors = instance.authors.all() # 取出所有作者
l = []
for author in authors:
l.append({'name': author.name, 'age': author.age})
return l
10、回顾
#1.Serializer类,需要序列化什么,必须写一个继承类,想要序列化什么字段,就在里面写字段,(source)
#2 序列化queryset(列表)对象和真正的对象,many=True的作用,instance=要序列化的对象
#3 反序列化 instance=要序列化的对象,data=request.data
#4 字段验证,序列化类中,给字段加属性,局部和全局钩子函数,字段属性validators=[check_author]
#5 当在视图中调用, 序列化对象.is_valid() booK_ser.is_valid(raise_exception=True) 只要验证不通过,直接抛出异常
#6 修改保存---》调用序列化列对象.save(),重写Serializer类 的update方法
def update(self, instance, validated_data):
# instance是Book这个对象
# validated_data是校验后的数据
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
instance.author = validated_data.get("author")
instance.publish = validated_data.get('publish')
instance.save() # book.save() 是django 的orm提供的
return instance
#7 序列化得到的字段, 序列化对象.data
#8 自定义Response对象
class MyResponse():
def __init__(self):
self.code = 100
self.msg = '成功'
@property
def get_dict(self):
return self.__dict__
#9 反序列化的新增 序列化类(data=request.data),如果只传了data,当调用序列化对象.save(),会触发序列化类的create方法执行,当传了instance和data时,调用 序列化对象.save(),会触发序列化类的update方法执行
#10 重写create方法,(可以很复杂)
def create(self, validated_data):
instance = Book.objects.create(**validated_data)
return instance
#11 ModelSerializer跟Model做了对应
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = Book # 对应models.py中的模型
fields = '__all__' # 表示所有字段都序列化
# fields = ('name', 'price') # 序列化指定字段
# exclude = ('name',) # 除了name字段,其他都序列化,不能跟fields连用,写谁,就排除谁
# 给authors和publish加write_only属性
# name加max_len属性
extra_kwargs = {
'name': {'max_length': 8},
'publish': {'write_only': True},
'authors': {'write_only': True,'max_lenth':6,'min_length':4},
}
#12 如果在ModelSerializer中写一个局部钩子或全局钩子,跟之前一摸一样
#13 many=True能够序列化多条的原因-----》__new__是在__init__之前执行的,造出了一个空对象
#14 接口:为了统一子类的行为
、
本文来自博客园,作者:ExpiredSaury,转载请注明原文链接:https://www.cnblogs.com/saury/p/16976666.html