为什么要序列化

django 查询数据库返回的类型是  queryset 类型 而我们和前端通信使用的大多数是json类型,这个时候我们需要把 queryset的数据类型转换成python的数据类型然后在转换成json 的格式返回

在我们没使用  restframework 中的 序列化之前我们是这样做的

class RolesView(APIView):
def get(self,request,*args,**kwargs):
roles = models.Role.objects.all().values('id','title')
roles = list(roles)
ret = json.dumps(roles,ensure_ascii=False)
return HttpResponse(ret)

json.dumps 中的参数   ensure_ascii=False 意思是不把中文进行转义,即显示中文

restframework 中的序列化器就可以自动的帮助我们 把queryset 的数据类型转化成 python的数据类型

restframework 序列化的使用

建表  models.py

from django.db import models

class UserGroup(models.Model):
title = models.CharField(max_length=32) class UserInfo(models.Model):
user_type_choices = (
(1,'普通用户'),
(2,'VIP'),
(3,'SVIP'),
)
user_type = models.IntegerField(choices=user_type_choices) username = models.CharField(max_length=32,unique=True)
password = models.CharField(max_length=64) group = models.ForeignKey("UserGroup")
roles = models.ManyToManyField("Role") class UserToken(models.Model):
user = models.OneToOneField(to='UserInfo')
token = models.CharField(max_length=64) class Role(models.Model):
title = models.CharField(max_length=32)

添加Role

查询所有的角色,使用  restframework进行序列化基本的使用如下

  1 写一个序列化的类继承  serializers 或  ModelSerializer ,类属性是要序列化的数据库表中的字段(注意:这个要对应)

   2 把创建序列化对象Obj,把需要序列化的数据传入进去,如果有多条数据 many = True 否则为False

  3   通过json.dumps(Obj.data) 转化成json格式

views.py 代码如下

import json
from django.shortcuts import render,HttpResponse
from rest_framework.views import APIView
from . import models
from rest_framework import serializers #要先写一个序列化的类
class RolesSerializer(serializers.Serializer):
#Role表里面的字段id和title序列化
id = serializers.IntegerField()
title = serializers.CharField() class RolesView(APIView):
def get(self,request,*args,**kwargs):
     # 方式一 多条数据的情况:
# roles = models.Role.objects.all().values('id','title')
# roles = list(roles)
# ret = json.dumps(roles,ensure_ascii=False)
# 方式二 只有一条数据的情况
     roles = models.Role.objects.all()
# 序列化,两个参数,instance:接受Queryset(或者对象) mangy=True表示对Queryset进行处理,mant=False表示对对象进行进行处理
ser = RolesSerializer(instance=roles,many=True)
# 转成json格式,ensure_ascii=False表示显示中文,默认为True
ret = json.dumps(ser.data,ensure_ascii=False)
return HttpResponse(ret)

添加对应路由

urlpatterns = [
url(r'roles/$', views.RolesView.as_view()),
]

测试的结果如下:

进阶使用

上述的情况是普通的字段,如果是特殊的字段,那么我们又该如何去处理呢,我们来操作user表,表中的字段如下

class UserInfo(models.Model):
user_type_choices = (
(1,'普通用户'),
(2,'VIP'),
(3,'SVIP'),
)
user_type = models.IntegerField(choices=user_type_choices) username = models.CharField(max_length=32,unique=True)
password = models.CharField(max_length=64) group = models.ForeignKey("UserGroup")
roles = models.ManyToManyField("Role")

  

我们使用上述的方法对其所有的字段进行序列化代码如下

class UserInfoSerializer(serializers.Serializer):
user_type = serializers.CharField() # row.user_type
username = serializers.CharField()
password = serializers.CharField()
group = serializers.CharField()
roles = serializers.CharField() class UserInfoView(APIView):
def get(self,request,*args,**kwargs): users = models.UserInfo.objects.all() # 对象, Serializer类处理; self.to_representation
# QuerySet,ListSerializer类处理; self.to_representation
ser = UserInfoSerializer(instance=users,many=True)
ret = json.dumps(ser.data, ensure_ascii=False)
return HttpResponse(ret)

为其添加路由

urlpatterns = [
url('(?P<version>[v1|v2]+)/users/$', views.UserView.as_view(),name='uuu'),
url(r'parser/$', views.ParserView.as_view()),
url(r'roles/$', views.RolesView.as_view()),
url(r'userinfo/$', views.UserInfoView.as_view()),
]

测试的结果如下

情况一  对于数据库中自已选择的字段

  对于表中的 user_type是choices(1,2,3)我们想显示全称 ,解决的方法是 传入参数source="get_user_type_display" ,它会自动的帮我们执行 get_user_type_display方法

修改后的序列化器如下

class UserInfoSerializer(serializers.Serializer):
# user_type = serializers.CharField() # row.user_type
user_type = serializers.CharField(source="get_user_type_display") # row.get_user_type_display() username = serializers.CharField()
password = serializers.CharField()
group = serializers.CharField()
roles = serializers.CharField()

测试的结果如下

情况二对于外键(一对一)

  对于表中外键的字段gruop ,我们想显示与其关联的title字段的内容  ,解决的方法是还是通过传入参数source="group.title"  它会自动的去查找

修改后的序列化器如下

情况三 对于外键(多对多的情况)

  对于外键多对多的情况我们想显示其中的一些字段,这个时候由于是多对多它是一个可迭代的对象,所以不能直接向上面一对一的情况直接取,解决的方法这时候我们需要自定义方法来获取

特别需要注音的是

  1 如果  要显示外键多对多内容 要使用  roles = serializers.SerializerMethodField()

  2  还有就是自定义函数的函数名应该是  如果多对多的外键是roles 函数名则应该是 get_roles(self,role--->可以随命名)  ,如果是rls则函数名为get_rls

代码如下

class UserInfoSerializer(serializers.Serializer):
# user_type = serializers.CharField() # row.user_type
user_type = serializers.CharField(source="get_user_type_display") # row.get_user_type_display() username = serializers.CharField()
password = serializers.CharField()
# group = serializers.CharField()
group = serializers.CharField(source='group.title')
# roles = serializers.SerializerMethodField()
roles = serializers.SerializerMethodField() # 自定义显示
def get_roles(self,row): role_obj_list = row.roles.all() ret = []
for item in role_obj_list:
ret.append({'id':item.id,'title':item.title})
return ret

测试的结果如下

ModelSerializer 序列化器的使用

ModelSerializer 继承 的是Serializer ,所以我们在使用它的时候同样可以混合着 Serializer 使用,它主要是在序列化字段的时候做了一些简化可以简单的对字段进行批量的定义和全部序列

在用的时候需要注意的是  对于一些普通的字段不能调用的应该放入 列表中,要是向Serializer 中  password = serializers.CharField() 这样去使用会报错

基本使用

class UserInfoSerializer(serializers.ModelSerializer):

    class Meta:
model = models.UserInfo
fields = "__all__" # 序列话所有的字段
# fields = ['id','username','password','oooo','rls','group','x1'] # 对指定的字段进行批量处理

测试的结果如下

和Serializer混合使用

class UserInfoSerializer(serializers.ModelSerializer):
oooo = serializers.CharField(source="get_user_type_display") # row.user_type
rls = serializers.SerializerMethodField() # 自定义显示 class Meta:
model = models.UserInfo
# fields = "__all__"
fields = ['id','username','password','oooo','rls','group'] def get_rls(self, row):
role_obj_list = row.roles.all() ret = []
for item in role_obj_list:
ret.append({'id':item.id,'title':item.title})
return ret

测试结果如下

自动序列化连表(depth)

在使用 ModelSerializer 遇到连表的操作,需要我们结合 Serializer 混合使用,其实在ModelSerializer 中还有一个参数表示depth表示连表的深度可以自动的帮我们去取数据

 depth 表示夸几张表查询数据,官方建议的参数是 ( 0 ~ 10 )

修改后的序列化器如下所示:

class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
#fields = "__all__"
fields = ['id','username','password','group','roles']
#表示连表的深度
depth = 1 class UserInfoView(APIView):
'''用户的信息'''
def get(self,request,*args,**kwargs):
users = models.UserInfo.objects.all()
ser = UserInfoSerializer(instance=users,many=True)
ret = json.dumps(ser.data,ensure_ascii=False)
return HttpResponse(ret)

测试的结果如下

生成URL

有时候一些数据,我们需要生成url返回给用户,让用户再次请求获取想要的数据

 基本的使用如下:

  添加字段   group = serializers.HyperlinkedIdentityField(view_name='gp',lookup_field='group_id',lookup_url_kwarg='xxx')

  参数说明   view_name 是 需要生成的url 中的name    lookup_field 需要生成url的真实传入到额参数,  lookup_url_kwarg 需要生成url的形参

修改后的序列化器如下所示

class UserInfoSerializer(serializers.ModelSerializer):
group = serializers.HyperlinkedIdentityField(view_name='gp',lookup_field='group_id',lookup_url_kwarg='xxx')
class Meta:
model = models.UserInfo
# fields = "__all__"
fields = ['id','username','password','group','roles']
depth = 0 # 0 ~ 10

添加再次请求的类视图和序列化器

class GroupSerializer(serializers.ModelSerializer):

    class Meta:
model = models.UserGroup
fields = "__all__" class GroupView(APIView):
def get(self,request,*args,**kwargs):
pk = kwargs.get('xxx')
obj = models.UserGroup.objects.filter(pk=pk).first() ser = GroupSerializer(instance=obj,many=False)
ret = json.dumps(ser.data,ensure_ascii=False)
return HttpResponse(ret)

添加路由

urlpatterns = [
url('(?P<version>[v1|v2]+)/users/$', views.UserView.as_view(),name='uuu'),
url(r'parser/$', views.ParserView.as_view()),
url(r'roles/$', views.RolesView.as_view()),
url(r'userinfo/$', views.UserInfoView.as_view()),
url(r'^(?P<version>[v1|v2]+)/group/(?P<xxx>\d+)$', views.GroupView.as_view(),name='gp'),
]

测试的结果如下

用户请求数据验证

使用序列化器对用户传送的值进行非空的判断

添加类视图代码如下

class UserGroupSerializer(serializers.Serializer):
title = serializers.CharField(error_messages={'required':'标题不能为空'}) class UserGroupView(APIView): def post(self,request,*args,**kwargs):
ser = UserGroupSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data['title'])
else:
print(ser.errors) return HttpResponse('提交数据')

添加路由

url(r'usergroup/$', views.UserGroupView.as_view(),name='gp'),

  

测试传入的值为空的接口如下

传入的值为空,后台打印的数据如下

测试非空的值

后台打印的结果如下

自定义验证规则

自定义了一个规则,传入的值必须以老男人开头,否则验证不通过

完整的代码如下

class XXValidator(object):
def __init__(self, base):
self.base = base def __call__(self, value):
if not value.startswith(self.base):
message = '标题必须以 %s 为开头。' % self.base
raise serializers.ValidationError(message) def set_context(self, serializer_field):
"""
This hook is called by the serializer instance,
prior to the validation call being made.
"""
# 执行验证之前调用,serializer_fields是当前字段对象
pass class UserGroupSerializer(serializers.Serializer):
title = serializers.CharField(error_messages={'required':'标题不能为空'},validators=[XXValidator('老男人'),]) class UserGroupView(APIView): def post(self,request,*args,**kwargs):
ser = UserGroupSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data['title'])
else:
print(ser.errors) return HttpResponse('提交数据')

测试满足自定义规则的数据的结果如下

后台打印数据如下

测试不满足自定义规则

后台打印结果如下

write_only和write_only的区别

  write_only  包含这个字段只作用于反序 (即对前端传来的值做序列话),正序的时候会忽略该字段

  read_only  包含这个字段只作用于正序 (即查询数据库做序列化返回给前端),反序的时候会忽略该字段

方法字段

serializers.SerializerMethodField 会把一个字段变成一个方法的字段,所以要为这个字段定义一个方法,返回的值为作为该字段的值

实例如下

表结构

class Book(models.Model):
title = models.CharField(max_length=)
CHOICES = ((, "Python"), (, "Linux"), (, "go"))
category = models.IntegerField(choices=CHOICES)
pub_time = models.DateField()
publisher = models.ForeignKey(to="Publisher")
authors = models.ManyToManyField(to="Author") class Publisher(models.Model):
title = models.CharField(max_length=) class Author(models.Model):
name = models.CharField(max_length=)

序列化

class BookSerializer(serializers.ModelSerializer):

    publisher_info = serializers.SerializerMethodField(read_only=True)
authors_info = serializers.SerializerMethodField(read_only=True) def get_authors_info(self, obj):
authors_querset = obj.authors.all()
return [{"id": author.id, "name": author.name} for author in authors_querset] def get_publisher_info(self, obj):
publisher_obj = obj.publisher
return {"id": publisher_obj.id, "title": publisher_obj.title} class Meta:
model = Book
fields = "__all__"
# exclude=["id"]
# 会让你这些所有的外键关系变成read_only = True
# depth =
extra_kwargs = {"publisher": {"write_only": True}, "authors":{"write_only": True}}

简单实例 

class BookEditView(APIView):
def get(self, request, id):
book_obj = Book.objects.filter(id=id).first()
ser_obj = BookSerializer(book_obj)
return Response(ser_obj.data) 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.validated_data)
return Response(ser_obj.errors)

  

ModelSerializer 中 deep 使用注意事项

在使用  deep  是 会把所有的 外键关系变成  read_only = True ,解决这个问题,我们可以 通过   extra_kwargs 为其添加额外的参数配置

    class Meta:
model = Book
fields = "__all__"
# exclude=["id"]
# 会让你这些所有的外键关系变成read_only = True
depth = 1
extra_kwargs = {"publisher": {"write_only": True}, "authors":{"write_only": True}}

验证

-- 单个字段的验证  权重 222
def validate_字段名称(self, value):
不通过 raise serializers.ValidationError("错误信息")
通过 return value
-- 多个字段的验证 权重 333
def validate(self, attrs):
attrs 是所有字段组成的字典
不通过 raise serializers.ValidationError("错误信息")
通过 return attrs
-- 自定义的验证 权重 111
def my_validate(value):
不通过 raise serializers.ValidationError("错误信息")
通过 return value
配置
-- 给字段加validators=[my_validate]

简单用法  

    def validate_title(self, value):
print(2222)
# value就是title的值 对value处理
if "python" not in value.lower():
raise serializers.ValidationError("标题必须含有python")
return value def validate(self, attrs):
print(33333)
# attrs 字典有你传过来的所有的字段
print(attrs)
if "python" in attrs["title"].lower() or attrs["post_category"] == 1:
return attrs
else:
raise serializers.ValidationError("分类或标题不合符要求")

  

重写update方法

    def update(self, instance, validated_data):
# instance 更新的book_obj 对象
# validated_data 校验通过的数据
# ORM做更新操作
instance.title = validated_data.get("title", instance.title)
instance.pub_time = validated_data.get("pub_time", instance.pub_time)
instance.category = validated_data.get("post_category", instance.category)
instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
if validated_data.get("author_list"):
instance.authors.set(validated_data["author_list"])
instance.save()
return instance

 

重写create方法 

    def create(self, validated_data):
# validated_data 校验通过的数据 就是book_obj
# 通过ORM操作给Book表增加数据
print(validated_data)
book_obj = Book.objects.create(title=validated_data["title"], pub_time=validated_data["pub_time"], category=validated_data["post_category"], publisher_id=validated_data["publisher_id"])
print(book_obj)
book_obj.authors.add(*validated_data["author_list"])
return book_obj

  

过滤Filtering

对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持。

pip install django-filter

注册应用:

INSTALLED_APPS = [
"django_filters",
]

在配置文件中增加过滤后端的设置:

REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

  

在视图中添加filter_fields属性,指定可以过滤的字段

class BookListView(ListAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
filter_fields = ('btitle', 'bread')

  

Django rest framework(6)----序列化(2)的更多相关文章

  1. Django Rest framework 之 序列化

    RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...

  2. Django REST Framework的序列化器是什么?

    # 转载请留言联系 用Django开发RESTful风格的API存在着很多重复的步骤.详细可见:https://www.cnblogs.com/chichung/p/9933861.html 过程往往 ...

  3. Django Rest Framework(2)-----序列化详解(serializers)

    REST framework中的序列化类与Django的Form和ModelForm类非常相似.我们提供了一个Serializer类,它提供了一种强大的通用方法来控制响应的输出,以及一个ModelSe ...

  4. Django restful Framework 之序列化与反序列化

    1. 首先在已建好的工程目录下新建app命名为snippets,并将snippets app以及rest_framework app加到工程目录的 INSTALLED_APPS 中去,具体如下: IN ...

  5. Django rest framework之序列化小结

       最近在DRF的序列化上踩过了不少坑,特此结合官方文档记录下,方便日后查阅. [01]前言    serializers是什么?官网是这样的”Serializers allow complex d ...

  6. django rest framework serializers序列化

    serializers是将复杂的数据结构变成json或者xml这个格式的 serializers有以下几个作用: - 将queryset与model实例等进行序列化,转化成json格式,返回给用户(a ...

  7. DRF Django REST framework 之 序列化(三)

    Django 原生 serializer (序列化) 导入模块 from django.core.serializers import serialize 获取queryset 对queryset进行 ...

  8. django-插件django REST framework,返回序列化的数据

    官网: http://www.django-rest-framework.org 1.安装 pip install djangorestframework 2.在setting.py中注册app 中添 ...

  9. django rest framework serializers

    django rest framework serializers序列化   serializers是将复杂的数据结构变成json或者xml这个格式的 serializers有以下几个作用:- 将qu ...

  10. django rest framework 项目创建

    Django Rest Framework 是一个强大且灵活的工具包,用以构建Web API 为什么要使用Rest Framework Django REST Framework可以在Django的基 ...

随机推荐

  1. keil常用配置设置

    1.设置tab键为空格4个进入Configuration->Editor,设置如下: 2.代码自动补齐进入Configuration->Editor,设置如下: 3.使用快捷键实现批量注释 ...

  2. 使用这些 HTTP 头保护 Web 应用

    摘要: 安全是个大学问. 这是关于web安全性系列文章的第 三 篇,其它的可点击以下查看: Web 应用安全性: 浏览器是如何工作的 Web 应用安全性: HTTP简介 目前,浏览器已经实现了大量与安 ...

  3. 详解Vue Native

    译者按: 一家叫GeekyAnts的印度公司开发了Vue Native,基于React Native实现. 原文: Introducing Vue Native 译者: Fundebug 为了保证可读 ...

  4. Linux设备驱动之IIO子系统——Triggered buffer support触发缓冲支持

    Triggered buffer support触发缓冲支持 在许多数据分析应用中,能够基于某些外部信号(触发器)捕获数据是比较有用的. 这些触发器可能是: 数据就绪信号 连接到某个外部系统的IRQ线 ...

  5. 解决ViewGroup不调用onDraw()的问题

    今天在做项目的时候自定义了一个View,继承了LinearLayout,结果,里面的onDraw()方法一直无法被调用. 后来发现ViewGroup是默认不调用onDraw()方法的. 原因我们暂且不 ...

  6. Kotlin入门(32)网络接口访问

    手机上的资源毕竟有限,为了获取更丰富的信息,就得到辽阔的互联网大海上冲浪.对于App自身,也要经常与服务器交互,以便获取最新的数据显示到界面上.这个客户端与服务端之间的信息交互,基本使用HTTP协议进 ...

  7. java中的sql语句中如果有like怎么写

    我先是在SQL server中写了如下语句: 这样是顺利执行的,可是我把这句话复制到Java代码中打出来却报错了, 刚开始我还以为是前端没有传回来值,待我一句一句打印发现,它提示我rs没有next.到 ...

  8. Oracle database link中查询会开启事务吗?

    关于oracle database link,使用database link相关的查询语句是否会开启事务呢?我们知道,在数据库中一个简单的SELECT查询语句不会产生事务(select for upd ...

  9. spark-2.4.0-hadoop2.7-高可用(HA)安装部署

    1. 主机规划 主机名称 IP地址 操作系统 部署软件 运行进程 备注 mini01 172.16.1.11[内网] 10.0.0.11  [外网] CentOS 7.5 Jdk-8.zookeepe ...

  10. PowerShell执行脚本时“系统上禁止运行脚本”问题解决

    PowerShell执行脚本策略错误 错误信息:PowerShell运行脚本错误--"系统上禁止运行脚本" 原因:默认执行策略为Restricted 解决:执行Set-Execut ...