Serialzers 序列化组件

前言

  • 当做前后端分离的项目时,JSON是一个轻量级的数据交互格式。所有我们给前端数据的时候都要转成json格式,那就需要对我们从数据库拿到数据进行序列化

Django的序列化方法

  • 使用django,json转数据进行传输,(了解即可)
class BooksView(View):
def get(self, request):
# 获取数据库中的queryset数据
book_list = Book.objects.values("id", "title", "chapter", "pub_time", "publisher")
# 强转成列表类型
book_list = list(book_list)
# 如果我们需要取外键关联的字段信息 需要循环获取外键 再去数据库查然后拼接成我们想要的
ret = []
for book in book_list:
pub_dict = {}
pub_obj = Publish.objects.filter(pk=book["publisher"]).first()
pub_dict["id"] = pub_obj.pk
pub_dict["title"] = pub_obj.title
book["publisher"] = pub_dict
ret.append(book)
ret = json.dumps(book_list, ensure_ascii=False, cls=MyJson)
return HttpResponse(ret) # json.JSONEncoder.default()
# 解决json不能序列化时间字段的问题
class MyJson(json.JSONEncoder):
def default(self, field):
if isinstance(field, datetime.datetime):
return field.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(field, datetime.date):
return field.strftime('%Y-%m-%d')
else:
return json.JSONEncoder.default(self, field)
  • 由于太过于麻烦,所有我们可以使用DRF的序列化

字段和选项

  • 注意serializer不是只能为数据库模型类定义,也可以为非数据库模型定义。serializer是独立于数据库之外的存在

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_lenght 最小长度
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页面时,显示的字段帮助提示信息

DRF序列化的方法

1. 自定义序列化

  • 需要自定义所有字段,以及方法create,updata方法

  • 声明一个序列化类

    # 根据model.py中的字段对应写要显示的字段
    class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
    chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display")
    pub_time = serializers.DateField()
  • 将数据库中的数据传入序列化对象中

    from rest_framework.views import APIView
    from rest_framework.response import Response class BookView(APIView):
    def get(self, request):
    # 获取数据库中的数据
    book_list = Book.objects.all()
    # 实例化序列化对象, many= True 表示数据有多个,如果是一个则不需要
    ret = BookSerializer(book_list, many=True)
    # 给前端的数据
    return Response(ret.data)

2. 外键关系的序列化

from rest_framework import serializers
from .models import Book class PublisherSerializer(serializers.Serializer):
# read_only=True 表示的是给前端时显示,反序列时,不需要此字段
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=32) class UserSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(max_length=32)
age = serializers.IntegerField() class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=32)
CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display", read_only=True)
pub_time = serializers.DateField() publisher = PublisherSerializer(read_only=True)
# many= True 表示有多条数据
user = UserSerializer(many=True, read_only=True)

3. 反序列化

  • 当前端给我们发post请求的时候,前端给后端传数据的,我们需要对数据进行一些校验然后保存到数据库,或者对数据库中的数据进行更改,DRF的serializer也提供了方法

  • Serializer提供了is_valid()和save方法

  • url.py

    urlpatterns = [
    url(r'^list$', BooksView.as_view()),
    ]
  • 声明一个序列化类

    # serializers.py 文件
    class BookSerializer(serializers.Serializer):
    # read_only = True 表示前端不需要传该字段的数据,其他的都需要传
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
    chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display", read_only=True)
    # write_only = True 表示前端需要传这个字段的数据,
    w_chapter = serializers.IntegerField(write_only=True)
    pub_time = serializers.DateField() publisher = PublisherSerializer(read_only=True)
    user = UserSerializer(many=True, read_only=True) users = serializers.ListField(write_only=True)
    publisher_id = serializers.IntegerField(write_only=True)
    # post请求会执行该方法
    def create(self, validated_data):
    book = Book.objects.create(title=validated_data["title"], chapter=validated_data["w_chapter"], pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])
    book.user.add(*validated_data["users"])
    # 需要返回对象
    # 如果数据简单,
    # book = Book.objects.create(**validated_data)
    return book
    • 注意: 因为存在后端给前端显示的数据和前端给后端存储的数据有区别,所有要灵活运用read_only= True 和write_only=True ,俩个属性,
  • 反序列化

    class BookView(APIView):
    def get(self, request):
    book_list = Book.objects.all()
    ret = BookSerializer(book_list, many=True)
    return Response(ret.data)
    # 会执行序列化中的create方法
    def post(self, request):
    # book_obj = request.data
    print(request.data)
    # 将前端传来的数据传入序列化对象中
    serializer = BookSerializer(data=request.data)
    # 判断数据
    if serializer.is_valid():
    # 执行后端的create方法
    serializer.save()
    return Response(serializer.validated_data)
    # 否则将错误信息发回给前端
    return Response(serializer.errors)
  • 对数据进行编辑

    url.py

    urlpatterns = [
    url(r'book/(?P<pk>\d+)/', BookView.as_view(), name='book'),
    ]

    声明一个序列化类

    class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
    chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display", read_only=True)
    w_chapter = serializers.IntegerField(write_only=True)
    pub_time = serializers.DateField() publisher = PublisherSerializer(read_only=True)
    user = UserSerializer(many=True, read_only=True) users = serializers.ListField(write_only=True)
    publisher_id = serializers.IntegerField(write_only=True) def create(self, validated_data):
    book = Book.objects.create(title=validated_data["title"], chapter=validated_data["w_chapter"], pub_time=validated_data["pub_time"],
    publisher_id=validated_data["publisher_id"])
    book.user.add(*validated_data["users"])
    return book
    # put或者patch或执行该方法
    def update(self, instance, validated_data):
    instance.title = validated_data.get("title", instance.title)
    instance.chapter = validated_data.get("w_chapter", instance.chapter)
    instance.pub_time = validated_data.get("pub_time", instance.pub_time)
    instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
    if validated_data.get("users"):
    instance.user.set(validated_data.get("users"))
    instance.save()
    return instance

    view.py

    class BookView(APIView):
    def patch(self, request):
    print(request.data)
    book_id = request.data["id"]
    book_info = request.data["book_info"]
    book_obj = Book.objects.filter(pk=book_id).first()
    # partial= True 对部分数据进行修改
    serializer = BookSerializer(book_obj, data=book_info, partial=True)
    if serializer.is_valid():
    serializer.save()
    return Response(serializer.data)
    else:
    return Response(serializer.errors) # 这俩种方法是一样的只写其中一种
    def put(self, request, id):
    book_obj = Book.objects.filter(id=id).first()
    ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
    if ser_obj.is_valid():
    ser_obj.save()
    return Response(ser_obj.data)
    return Response(ser_obj.errors)

3.1 view四个方法的运用

-- get 请求
def get(self, request):
queryset = Book.objects.all()
ser_obj = BookSerializer(queryset, many=True)
return Response(ser_obj.data) -- post请求
def post(self, request):
data = request.data
ser_obj = BookSerializer(data=request.data)
if ser_obj.is_valid():
ser_obj.save()
# ser_obj.validated_data
return Response(ser_obj.data)
else:
return Response(ser_obj.errors) -- put/patch请求
def put(self, request, id):
data = request.data
book_obj = Book.objects.filter(id=id).first()
ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True) # partial表示局部更新
if ser_obj.is_valid():
ser_obj.save()
# ser_obj.validated_data
return Response(ser_obj.data)
else:
return Response(ser_obj.errors)

4.验证

  • 优先级从高到低: 自定义>单独验证>多个字段验证

  • 如果我们需要对某些字段进行自定义验证,DRF也给我们提供了钩子方法

  • 一 对单个数据进行验证, 格式必须是validate_需要验证的字段名(self, value):

    class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32)
    # 省略了一些字段 跟上面代码里一样的
    # 。。。。。
    # 格式必须是validate_需要验证的字段名(self, value)
    def validate_title(self, value):
    if "python" not in value.lower():
    raise serializers.ValidationError("标题必须含有Python")
    return value
  • 对多个数据进行验证

    class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
    chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display", read_only=True)
    w_chapter = serializers.IntegerField(write_only=True)
    pub_time = serializers.DateField()
    date_added = serializers.DateField(write_only=True)
    # 新增了一个上架时间字段
    # 省略一些字段。。都是在原基础代码上增加的
    # 。。。。。。 # 对多个字段进行验证 要求上架日期不能早于出版日期 上架日期要大
    def validate(self, attrs):
    if attrs["pub_time"] > attrs["date_added"]:
    raise serializers.ValidationError("上架日期不能早于出版日期")
    return attrs
  • 定义一个验证器

    def my_validate(value):
    if "敏感词汇" in value.lower:
    raise serializers.ValidationError("包含敏感词汇,请重新提交")
    return value class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=32, validators=[my_validate])
    # 。。。。。。

ModelSerializer

  • 现在我们已经清楚了Serializer的用法,会发现我们所有的序列化跟我们的模型都紧密相关~

    那么,DRF也给我们提供了跟模型紧密相关的序列化器ModelSerializer

      -- 它会根据模型自动生成一组字段

      -- 它简单的默认实现了.update()以及.create()方法

1.定义一个ModelSerializer序列化器

class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
# fields = ["id", "title", "pub_time"]
# exclude = ["user"]
# 分别是所有字段 包含某些字段 排除某些字段

2.外键关联的序列化

自动序列化连表操作,可以使用depth来进行快捷的跨表操作,官方建议是0~10层,但是最好用到3或者4层就可以了

注意:当序列化类MATE中定义了depth时,这个序列化类中引用字段(外键)则自动变为只读

class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
# fields = ["id", "title", "pub_time"]
# exclude = ["user"]
# 分别是所有字段 包含某些字段 排除某些字段
depth = 1
# depth 代表找嵌套关系的第几层

3.自定义字段对覆盖默认字段

我们可以声明一些字段来覆盖默认字段,来进行自定制~

比如我们的选择字段,默认显示的是选择的key,我们要给用户展示的是value。

class BookSerializer(serializers.ModelSerializer):
chapter = serializers.CharField(source="get_chapter_display", read_only=True) class Meta:
model = Book
fields = "__all__"
# fields = ["id", "title", "pub_time"]
# exclude = ["user"]
# 分别是所有字段 包含某些字段 排除某些字段
depth = 1

4.meta中的其它关键字参数

class BookSerializer(serializers.ModelSerializer):
chapter = serializers.CharField(source="get_chapter_display", read_only=True) class Meta:
model = Book
fields = "__all__"
# fields = ["id", "title", "pub_time"]
# exclude = ["user"]
# 分别是所有字段 包含某些字段 排除某些字段
depth = 1
# read_only_fields 表示只读
read_only_fields = ["id"]
extra_kwargs = {"title": {"validators": [my_validate,]}}
  • read_only_fields 表示id为只读,

  • extra_kwargs 选项在字段上指定任意附加关键字参数。与 read_only_fields 的情况一样,这意味着你不需要在序列化类中显式声明该字段。

  • 该选项是一个字典,将字段名称映射到关键字参数字典。例如:

    class CreateUserSerializer(serializers.ModelSerializer):
    class Meta:
    model = User
    fields = ('email', 'username', 'password')
    extra_kwargs = {'password': {'write_only': True}}

5 post以及patch/put请求

  • 由于depth会让我们外键变成只读,所以我们再定义一个序列化的类,其实只要去掉depth就可以了~~
class BookSerializer(serializers.ModelSerializer):
chapter = serializers.CharField(source="get_chapter_display", read_only=True) class Meta:
model = Book
fields = "__all__"
# fields = ["id", "title", "pub_time"]
# exclude = ["user"]
# 分别是所有字段 包含某些字段 排除某些字段
read_only_fields = ["id"]
extra_kwargs = {"title": {"validators": [my_validate,]}}

6 SerializerMethodField

  • 针对于多对多表数据的显示,可以使用SerializerMethodField,来自定义显示

外键关联的对象有很多字段我们是用不到的都传给前端会有数据冗余就需要我们自己去定制序列化外键对象的哪些字段~~

class BookSerializer(serializers.ModelSerializer):
chapter = serializers.CharField(source="get_chapter_display", read_only=True)
user = serializers.SerializerMethodField()
publisher = serializers.SerializerMethodField() def get_user(self, obj):
# obj是当前序列化的book对象
users_query_set = obj.user.all()
return [{"id": user_obj.pk, "name": user_obj.name} for user_obj in users_query_set] def get_publisher(self, obj):
publisher_obj = obj.publisher
return {"id": publisher_obj.pk, "title": publisher_obj.title} class Meta:
model = Book
fields = "__all__"
# fields = ["id", "title", "pub_time"]
# exclude = ["user"]
# 分别是所有字段 包含某些字段 排除某些字段
read_only_fields = ["id"]
extra_kwargs = {"title": {"validators": [my_validate,]}}

7. 用ModelSerializer改进上面Serializer的完整版

class BookSerializer(serializers.ModelSerializer):
dis_chapter = serializers.SerializerMethodField(read_only=True)
users = serializers.SerializerMethodField(read_only=True)
publishers = serializers.SerializerMethodField(read_only=True) def get_users(self, obj):
# obj是当前序列化的book对象
users_query_set = obj.user.all()
return [{"id": user_obj.pk, "name": user_obj.name} for user_obj in users_query_set] def get_publishers(self, obj):
publisher_obj = obj.publisher
return {"id": publisher_obj.pk, "title": publisher_obj.title} def get_dis_chapter(self, obj):
return obj.get_chapter_display() class Meta:
model = Book
# fields = "__all__"
# 字段是有序的
fields = ["id", "title","dis_chapter", "pub_time", "publishers", "users","chapter", "user", "publisher"]
# exclude = ["user"]
# 分别是所有字段 包含某些字段 排除某些字段
read_only_fields = ["id", "dis_chapter", "users", "publishers"]
extra_kwargs = {"title": {"validators": [my_validate,]}, "user": {"write_only": True}, "publisher": {"write_only": True},
"chapter": {"write_only": True}}

返回URL的连接

详情见网址:https://www.cnblogs.com/wupeiqi/articles/7805382.html中的序列化中的url

Serialzers 序列化组件的更多相关文章

  1. DjangoRestFramework学习二之序列化组件、视图组件 serializer modelserializer

      DjangoRestFramework学习二之序列化组件.视图组件   本节目录 一 序列化组件 二 视图组件 三 xxx 四 xxx 五 xxx 六 xxx 七 xxx 八 xxx 一 序列化组 ...

  2. cvb源码分析,resful规范,drf,drf序列化组件,95

    1 CBV的源码分析 -Class Base View(基于类的视图) -Function Base View(基于函数的视图) -def as_view 类方法 -def view:类方法内部,闭包 ...

  3. rest-framework之APIView 序列化组件

    rest-framework之APIView 一 安装djangorestframework 方式一:pip3 install djangorestframework 方式二:pycharm图形化界面 ...

  4. drf 之序列化组件

    序列化 把Python中对象转换为json格式字符串 反序列化 把json格式转为为Python对象. 用orm查回来的数据都是都是一个一个的对象, 但是前端要的是json格式字符串. 序列化两大功能 ...

  5. DRF 序列化组件

    Serializers 序列化组件 Django的序列化方法 class BooksView(View): def get(self, request): book_list = Book.objec ...

  6. python全栈开发day99-DRF序列化组件

    1.解释器组件源码分析 https://www.processon.com/view/link/5ba0a8e7e4b0534c9be0c968 2.基于CBV的接口设计 1).django循环que ...

  7. Serializers 序列化组件

    Serializers 序列化组件   为什么要用序列化组件 当我们做前后端分离的项目~~我们前后端交互一般都选择JSON数据格式,JSON是一个轻量级的数据交互格式. 那么我们给前端数据的时候都要转 ...

  8. django rest_framework 序列化组件详解

    为什么要用序列化组件 当我们做前后端分离的项目,我们前后端交互一般都选择JSON数据格式,JSON是一个轻量级的数据交互格式. 那么我们给前端数据的时候都要转成json格式,那就需要对我们从数据库拿到 ...

  9. DRF框架之 serializers 序列化组件

    1. 什么是序列化,其实在python中我们就学了序列化工具json工具,就是吧信息存为类字典形式 2. DRF框架自带序列化的工具: serializers 3. DRF框架 serializers ...

随机推荐

  1. Solution -「LOJ #6053」简单的函数

    \(\mathcal{Description}\)   Link.   积性函数 \(f\) 满足 \(f(p^c)=p\oplus c~(p\in\mathbb P,c\in\mathbb N_+) ...

  2. MySQL安装,使用问题汇总

    一,安装问题 mysqld install时出现:The service already exists! 报错原因:以前机器上装过mysql没有卸载干净 解决方案: C:\windows\system ...

  3. CentOS 7 升级 gcc-4.8.5 到 gcc-5.4.0

    文章目录 1.环境介绍 2.下载gcc-5.4.0源码包 3.编译安装gcc 4.验证gcc版本 5.更新gcc连接 1.环境介绍 [root@localhost ~]# gcc -v Using b ...

  4. MySQL 5.7 基于GTID主从复制+并行复制+半同步复制

    环境准备 IP HOSTNAME SERVICE SYSTEM 192.168.131.129 mysql-master1 mysql CentOS7.6 192.168.131.130 mysql- ...

  5. JAVA8学习——Stream底层的实现二(学习过程)

    继续深入Stream的底层实现过程 2.spliterator() 接上 https://www.cnblogs.com/bigbaby/p/12159495.html 我们这次回到最开始源码分析的地 ...

  6. 关于 ios 动画枚举翻译

    例子 + (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewA ...

  7. docker下安装nginx,启动ngixn,修改nginx配置等--超详细

    1.获取nginx版本 docker中nginx版本信息:https://hub.docker.com/_/nginx?tab=tags&page=1&ordering=last_up ...

  8. python https 无法访问 SSLError("Can\'t connect to HTTPS URL because the SSL module is not available

    1,需要检查python 安装的时候是否支持 https 进入python 环境,import ssl 如果正常导入就可以使用https,不能导入就需要进入下一步. 2,查看系统是否安装了openss ...

  9. bugku 神秘的文件

      题目链接: https://ctf.bugku.com/challenges#%E7%A5%9E%E7%A7%98%E7%9A%84%E6%96%87%E4%BB%B6 工具准备: 1.PC 2. ...

  10. BI工具数据可视化效果哪家强?我选这款!

    BI工具是商业智能(Business Intelligence)软件的英文缩写.目前,商业智能通常被理解为将企业中现有的数据转化为知识,帮助企业做出明智的业务经营决策的工具. 企业经常会为如何选择BI ...