序列化器介绍、Serializer的使用、常用字段类型与参数、反序列化的新增、查看、删除修改数据、局部与全局钩子、ModelSerializer模型类序列化器
今日内容概要
- 序列化器介绍
- Serializer的使用
- 反序列化之新增
- 反序列化之修改
- ModelSerializer模型类序列化器
- 额外添加参数
内容详细
1、序列化器介绍
# 序列化器:就是 类
# 作用:
1. 序列化,序列化器会把模型对象(qs,book)转换成字典,经过response以后变成json字符串
2. 反序列化,把客户端发(前端)送过来的数据,
经过request以后变成字典(data),序列化器可以把字典转成模型 存到数据库中
3. 反序列化,完成数据校验功能
前端传入的数据是否合法,长度够不够
# 使用方式
第一步:写一个类:必须继承drf中的Serializer及其子类
第二步:在类中写要序列化的字段
要序列化哪些,就写哪些,不序列化的不写
第三步:使用序列化类,视图类中用
得到序列化类对象 对象.data,通过Response返回给前端
2、Serializer的使用
路由 urls.py
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()),
]
"""
通过postman测试正常
如果通过浏览器访问 要先在配置文件中注册app: rest_framework
否则会直接报错 因为rest_framework是作为软件使用的
"""
视图类 views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Book
from .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) # 字典,列表,字符串都行
模型类 models.py
from django.db import models
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)
创建序列化类 新建 serializer.py
from rest_framework import serializers
# 第一步:写一个类:必须继承drf中的Serializer及其子类
# drf提供的类:Serializer
class BookSerializer(serializers.Serializer):
# 第二步:在类中写要序列化的字段
# max_length=32,min_length=3 反序列化保存校验数据的时候用
name = serializers.CharField(max_length=32, min_length=3)
# price=serializers.DecimalField()
price = serializers.CharField() # models中使用了DecimalField,这个位置使用了CharField会把小数类型转成字符串
author = serializers.CharField()
# 第三步:使用序列化类,视图类中用
2.1、常用字段类型
# models中CharField,DecimalField.....
# 要记住的:
CharField
IntegerField
FloatField
DecimalField
DateTimeField
DateField
# models中没有的 是反序列化的时候,前端传入的:
ListField
DictField
eg:前端传入的数据
{name:lqz,age:19,hobby:[篮球,足球],wife:{name:lyf,age:38}}
hobby wife字段 就要使用 ListField来接收
字段 | 字段构造方式 |
---|---|
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.2、字段参数
# 写在字段类中的参数
如:max_length...
# 重点:
read_only:表明该字段仅用于序列化输出,默认False
如果read_only=True,这个字段只用来做序列化 把对象json 给前端
write_only:表明该字段仅用于反序列化输入,默认False
如果read_only=write_only,这个字段只用来做反序列化前端json存到数据库
# 举例
name=serializers.CharField(max_length=32,min_length=3)
price=serializers.CharField(write_only=True)
author=serializers.CharField(write_only=True)
# 括号内什么都不写,表示既序列化,又反序列化:
前端都能看到
# 序列化给前端,前端看到的字段样子:
前端只能看到name
# 反序列化,前端需要传什么过来:
name,price,author都传
# 如果写成:
price=serializers.CharField(write_only=True,read_only=True)
本身就产生了逻辑矛盾 所以不能这样写
2.4、序列化时,定制序列化的字段
"""将前端获取的数据 变成自己想要的模样"""
# 在序列化类中添加:
# 定制序列化的字段两种方案 :key(字段名),value(方法返回)都可以定制
# 作用?比如author关联了外键,想取出作者详情
# 伪代码:
# author_info = serializers.SerializerMethodField()
# def get_author_info(self,obj):
# return {'name':obj.author.name,'age':obj.author.age}
# 第一种方案:在序列化类中写
# price_info = serializers.SerializerMethodField() # SerializerMethodField()必须配合一个方法,方法名: get_字段名
# def get_price_info(self, obj): # 方法返回什么,字段就是什么,obj是当前序列化到的单个对象
# return "价格是:"+str(obj.price) # python是动态强类型语言 强类型是:不同类型之间不允许直接运算
# 第二种方案:在models中写方法,这里字段名就是models的方法名,price_info方法返回什么,这个字段就是什么
price_info = serializers.CharField(read_only=True) # 只用来做序列化
authors = serializers.ListField() # 返回的数据类型是什么 就用什么字段类型 CharField DecimalField
# 在模型类中添加:
# 表模型中写方法
@property # 把方法包装成数据属性
def price_info(self):
return "价格是:" + str(self.price)
# 伪代码
def authors(self):
# 如果有外键关联,假设作者有好几个
return [{'name': 'lqz', 'age': 10}, {'name': 'lqz', 'age': 10}]
3、反序列化之新增
# 反序列化
第一步:把前端传入的数据,放到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
序列化类添加 serializer.py
from .models import Book
# 重写create方法
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对象
视图类添加 views.py
def post(self, request):
# 反序列化,保存使用data参数
ser = BookSerializer(data=request.data) #
# 校验数据
if ser.is_valid(): # 如果是true表示数据校验通过,通过,就保存
# 如果instance为None,调用save本质会调用create--》父类create直接抛异常,所以我们要重写
ser.save() # 就会保存,重写create方法,如果不重写,我们不知道存到哪个表中
return Response(ser.data)
return Response({'code': 101, 'msg': '数据校验失败', 'err': ser.errors})
补充国际化
# 配置文件中改
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False
4、反序列化之修改
序列化类添加 serializer.py
# 第二步:在类中写要序列化的字段
id= serializers.CharField(read_only=True)
# 重写update方法
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对象
视图类添加 views.py
# 修改删除功能
class BookDetailView(APIView):
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})
路由 urls.py
# 修改删除功能
path('books/<int:pk>', views.BookDetailView.as_view()),
5、查询单条与删除
# 视图类添加 views.py
# 修改删除功能
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})
6、反序列化之局部和全局钩子
# 序列化类添加 serializer.py:
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
7、ModelSerializer模型类序列化器及额外添加参数
# 以后使用ModelSerializer跟表模型做绑定,以后这个用的多,不需要重写update和create方法了
# 路由 urls.py添加:
# 查询新增
path('books1/', views.BookView1.as_view()),
# 修改删除功能
path('books1/<int:pk>', views.BookDetailView1.as_view()),
# 序列化类添加 serializer.py
class BookSerializer1(serializers.ModelSerializer):
class Meta:
model = Book # 跟那个表有关系
# fields='__all__' # 所有字段
# id是从表模型中映射过来的,auto,它会不要求你传
# price_info:它不是数据库中字段
# 即便扩写的字段,也要在fields中注册
fields = ['id', 'name', 'price', 'author', 'price_info']
# 原来的字段参数,通过extra_kwargs传进去
extra_kwargs = {
'name': {'write_only': True, 'max_length': 8, 'min_length': 3}
} # 'write_only': True name字段将不会显示在前端页面
# 重写字段
# 局部和全局钩子跟之前一样
# 复制添加查询修改相关功能并修改:
# 查询添加功能
class BookView1(APIView):
def get(self, request):
# 查出来的数据做序列化
book_list = Book.objects.all()
# instance:要序列化的对象 qs对象/单个对象
# many:如果是qs对象,many=True,如果是单个对象many=False
ser = BookSerializer1(instance=book_list, many=True) # 传入初始化的参数instance=None, data=empty
# ser.data使用模型类对象序列化后的字典
return Response(ser.data) # 字典,列表,字符串都行
# 添加功能
def post(self, request):
# 反序列化,保存使用data参数
ser = BookSerializer1(data=request.data) #
# 校验数据
if ser.is_valid(): # 如果是true表示数据校验通过,通过,就保存
# 如果instance为None,调用save本质会调用create--》父类create直接抛异常,所以我们要重写
ser.save() # 就会保存,重写create方法,如果不重写,我们不知道存到哪个表中
return Response(ser.data)
return Response({'code': 101, 'msg': '数据校验失败', 'err': ser.errors})
# 修改删除功能
class BookDetailView1(APIView):
def get(self, request, pk):
book = Book.objects.filter(pk=pk).first()
ser = BookSerializer1(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 = BookSerializer1(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})
# 模型类 models.py注释掉其余功能:
from django.db import models
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)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通