drf序列化和反序列化

一、自定义序列化

# models.py
from django.db import models
class User(models.Model):
CHOICE_SEX = ((0, '男'), (1, '女'))
name = models.CharField(max_length=100)
height = models.DecimalField(max_digits=6, decimal_places=2, default=1.85)
age = models.IntegerField(default=0)
icon = models.ImageField(upload_to='icon', default='default.jpg')
sex = models.IntegerField(choices=CHOICE_SEX)
class Meta:
db_table = 'db_user'
verbose_name = '用户表'
verbose_name_plural = verbose_name def __str__(self):
return self.name
# urls.py
urlpatterns = [
url(r'^books/$', views.MyAPIView.as_view()),
url(r'^books/(?P<pk>\d+)/', views.MyAPIView.as_view()),
# 在路由配置向外面开放的接口 media
url(r'^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT})
]
from api import models
from django.conf import settings
from rest_framework.response import Response
from rest_framework.views import APIView
class MyAPIView(APIView):
def get(self, *args, **kwargs):
pk = kwargs.get("pk", None)
if pk:
print(pk)
user_obj = models.User.objects.filter(pk=pk).first()
return Response({
"status": 0,
'msg': "get ok",
'result': {
"name": user_obj.name,
'age': user_obj.age,
"icon": f'http://127.0.0.1:8000{settings.MEDIA_URL}{user_obj.icon}',
"sex": user_obj.get_sex_display()
}
})
else:
user_list = []
user_list_obj = models.User.objects.all() for user_obj in user_list_obj:
user_list.append(
{
'result': {
"name": user_obj.name,
'age': user_obj.age,
"icon": f'http://127.0.0.1:8000{settings.MEDIA_URL}{user_obj.icon}',
"sex": user_obj.get_sex_display()
}
}
)
print(user_list)
return Response({ "status": 0,
'msg': "get ok",
'result': user_list
}) def post(self, *args, **kwargs):
return Response({
"status": 1
})

总结:

  1. 通过ORM操作获取数据库拿到资源数据
  2. 将获取的的数据进行序列化,序列化之后将数据返回给前台的数据
  3. 通过Response返回格式化后的数据

1.1 设置国际化

# 在settings中设置了国际化才可以显示中文
LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True USE_TZ = False

二、通过视图类的序列化和反序列化

# 在settings中设置了国际化才可以显示中文
LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True USE_TZ = False

2.1通过视图类序列化

自定义序列化类

# 创建自定义.py并创建序列化类
class MySerialize(serializers.Serializer):
name = serializers.CharField()
age = serializers.IntegerField()
# icon = serializers.ImageField()
# sex = serializers.IntegerField()
# 小数字段,必须要设置参数
height = serializers.DecimalField(max_digits=6, decimal_places=3) # 自定义字段
gender = serializers.SerializerMethodField()
icon = serializers.SerializerMethodField() # 自定义序列化字段,序列化的属性值由方法来提供,
# 方法的名字:固定为 get_属性名,
# 方法的参数:序列化对象,序列化的model对象
# 强烈建议自定义序列化字段名不要与model已有的属性名重名 def get_gender(self, obj):
# print(obj, type(obj)) # obj类<class 'api.models.User'>
# print(self, type(self)) # class 'api.myserialize.MySerialize'>
return obj.get_sex_display() def get_icon(self, obj):
return f'http://127.0.0.1:8000/media/{obj.icon}'

视图类


# 通过serialize实现序列化
from .myserialize import MySerialize
class MyAPIView(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get("pk", None)
if pk:
user_obj = models.User.objects.filter(pk=pk).first()
# 自定义单序列化
my_serialize = MySerialize(user_obj)
print(my_serialize.data)
# if my_serialize.is_valid():
# res = my_serialize
return Response({
"status": 0,
'msg': "get ok",
'result': my_serialize.data }) else:
user_list_obj = models.User.objects.all()
# 群序列化
my_serialize = MySerialize(user_list_obj, many=True) print(my_serialize.data, type(my_serialize.data))
return Response({ "status": 0,
'msg': "get ok",
'result': my_serialize.data
})

总结:

  1. 直接将要序列化的数据传给序列化类
  2. 要序列化的数据如果是单个对象,序列化的参数many为False,数据如果是多个对象(list,queryset)序列化的参数many为True
  3. 序列化类的中字段必须与model中字段属性同名,如果不参与序列化的model属性,在序列化类中不做声明,也不会返回
  4. 可以自定义序列化字段,自定义序列化字段用 SerializerMethodField() 作为字段类型,序列化的属性有方法类提供,方法的名字:get_属性名,方法参数:序列化对象,序列化的model对象,注意自定义的序列化字段不要与model已有字段属性重名,返回方法的返回值

2.2通过视图类反序列化

class UserCreateSerialize(serializers.Serializer):
# 系统校验规则
# 系统必须反序列化的字段,序列化的字段,序列化属性名不是必须有与model属性名字对应
# 但是与之对应会方便序列化将校验通过的数据与数据库进行交互,
name = serializers.CharField(min_length=3, max_length=6, required=False,error_messages={
'required': "姓名必填",
"min_length": "太短"
})
# # 系统可选的反序列化字段:没有提供不进行校验(数据库中有默认值或可以为空),提供了就进行校验
age = serializers.IntegerField(min_value=3, max_value=6, required=False)
# icon = serializers.ImageField()
sex = serializers.IntegerField()
# 小数字段,必须要设置参数
height = serializers.DecimalField(max_digits=6, decimal_places=3) pwd = serializers.CharField(min_length=3, max_length=64) # 自定义反序列化字段:一定参与校验,且要在校验过程中,将其从入库的数据中取出,剩余与model对应的数据才会入库
re_pwd = serializers.CharField(min_length=3, max_length=64) par = serializers.CharField(max_length=10) # 自定义校验规则:局部钩子,全局钩子
# 局部钩子: validate_字段名(slef, 字段值)
# 规则: 成功返回value,校验错误抛异常
def validate_par(self, value):
if 'rand' in value.lower():
raise serializers.ValidationError("名字不能有randy")
return value # 全局钩子:validate(self, 所有校验的数据字典)
# 规则:成功返回attrs,失败抛异常
def validate(self, attrs):
pwd = attrs.get("pwd")
re_pwd = attrs.pop('re_pwd')
if pwd != re_pwd:
raise serializers.ValidationError({"re_pwd": "两次密码不能一样!"})
return attrs # create重写,
def create(self, validated_data):
return models.User.objects.create(**validated_data) class MyAPIView(APIView):
# 单增和群增
def post(self, request, *args, **kwargs):
# 从请求对象中拿到前台的数据
# 校验数据是否合法
# 反序列化成后台Model对象与数据交互
request_data = request.data
user_seria = UserCreateSerialize(data=request_data) # 调用反序列化的校验规则,系统规则,自定义规则(局部钩子,全局钩子)
result = user_seria.is_valid()
if result:
# 校验通过,可以与数据库进行交互增 create,该(update)
user_obj = user_seria.save() return Response({
'status': 0,
'msg': 'ok',
'results': MySerialize(user_obj).data })
else: # 校验失败,返回错误信息,在使用 .errors必须先要调用 is_valid()方法
return Response({
"status": 1,
"msg": user_seria.errors, }, status=status.HTTP_400_BAD_REQUEST
)

总结:

  1. 在视图类中,从请求对象中获取前台的数据,校验前台数据是否合法,然后将合法的数据返回给Model对象与数据进行交互,保存数据
  2. 反序列化的数据如果是单个数据,反序列化的参数mangy为False,数据如果是多个字典的列表,反序列化的参数many为True
  3. user_seria.errors,在报错的时候一定要先使用 is_valid()函数
  4. 反序列化类:系统的字段可以在Filed类型中设置系统校验的规则(name=serializers.CharField(min_length=3))
  5. required校验规则对该字段是必校验还是可选校验字段(默认required为True,数据库字段有默认值或可以为空的字段可以将required赋值为False)
  6. 自定义的反序列字段,设置系统校验规则同系统字段,但是需要在自定义校验规则中(局部、全局钩子)将自定义反序列化字段取出(返回剩余的数据与数据库交互)
  7. 局部钩子的方法命名 validate_属性名(self, 属性的value),校验规则为 成功返回属性的value 失败抛出校验错误的异常
  8. 全局钩子的方法命名 validate(self, 所有属性attrs),校验规则为 成功返回attrs 失败抛出校验错误的异常
  9. 校验有个顺序先校验全部声明的字段,只有全部校验成功之后才会去校验局部钩子,然后在校验全局钩子;,
  10. 反序列化需要重写create,update方法

三、ModelSerializer类实现序列化和反序列化

3.1 序列化

from rest_framework.serializers import ModelSerializer
# 自定反序列化类
class UserModelSerializer(ModelSerializer):
# source指定数据的来源,"product.product_id"是models中表的字段
product_id = serializers.IntegerField(source="product.product_id")
image_url = serializers.ImageField(source="image.image_url")
class Meta:
model = models.User
fields = ["name", "age", "height", "sex", 'gender'] # 序列化字段 # 自定义插拔序列化字段(在model类中实现):
#替换了在Serializer类中自定义的序列化字段(SerializerMethodField)
# 自定义插拔序列化字段一定不参与反序列化过程
@property
def gender(self):
return self.get_sex_display() from .myserialize import UserModelSerializer # 视图类
class MyAPIView(APIView):
# 单查和群查
def get(self, request, *args, **kwargs):
pk = kwargs.get("pk", None)
if pk:
user_obj = models.User.objects.filter(pk=pk).first() if not user_obj:
return Response(data={"status": 1, 'msg': "数据不存在"}) # 序列化数据context 将request传递过去则会自动凭借url的资源,比如图片
user_data = UserModelSerializer(user_obj, many=False,context={"request": request}).data return Response({
'status': 0,
'msg': '单查 ok',
'results': user_data
}) # 群查
user_query = models.User.objects.all()
# 获取序列化
user_list_data = UserModelSerializer(user_query, many=True).data return Response({
"status": 0,
"msg": "群查 ok",
"results": user_list_data
})

3.2 反序列化

from rest_framework.serializers import ModelSerializer
# 自定反序列化类
from rest_framework.serializers import ModelSerializer class UserModelSerializer(ModelSerializer):
# 将序列化类与Model类进行绑定
# 设置序列化与反序列化所有字段(并划分序列化字段与反序列化字段)
# 设置反序列化的局部与全局钩子 # 自定义反序列化字段,校验规则只能生命自定义反序列化字段是设置,且一定要写write_only
re_pwd = serializers.CharField(min_length=3, max_length= 5, write_only=True) class Meta:
model = models.User
fields = ["name", "age", "height", "sex", 'gender', "pwd", "re_pwd"]
extra_kwargs = {
"name": {
'required': True,
"min_length": 3,
"error_messages": {
"min_length": "太短了"
}
}, "age": {
# 数据库中有默认值或可以为空字段, required默认为false,前台发送的数据不会进行校验,只有为true时候才会进行校验
"required": True,
'min_value': 5,
"read_only": True, # 只参与序列化,不参与反序列化进行校验
},
"pwd": {
"required": True,
"write_only": True, # 只参与反序列化 设置这个就是在反序列化的时候不会返回给前台,不会序列化 },
"height": {
# 只参与序列化,不参与反序列化进行校验,就是校验数据传来了height这个参数,不会对数据进行校验只会返回原先的数据或者是默认的数据
"read_only": True,
} } # 局部钩子
def validate_name(self, value):
if 'randy' in value.lower():
raise serializers.ValidationError('名字中不能有randy')
return value
# 全局钩子
def validate(self, attrs):
pwd = attrs.get('pwd')
# 一定要移除
re_pwd = attrs.pop('re_pwd')
if pwd != re_pwd:
raise serializers.ValidationError({'re_pwd': '两次密码不一致'})
return attrs from .myserialize import UserModelSerializer
# 视图类
class MyAPIView(APIView):
# 单增和群增
def post(self, request, *args, **kwargs):
# 获取校验数据
request_data = request.data
user_seria = UserModelSerializer(data=request_data) # 校验失败直接抛异常,反馈异常信息给前台,只要校验通过代码才会往下执行
# result = user_seria.is_valid(raise_exception=True)
result = user_seria.is_valid(raise_exception=True)
if result:
# 校验通过,可以与数据库进行交互增 create,该(update)
user_obj = user_seria.save() return Response({
'status': 0,
'msg': 'ok',
'results': UserModelSerializer(user_obj).data })
else: # 校验失败,返回错误信息,在使用 .errors必须先要调用 is_valid()方法
return Response({
"status": 1,
"msg": user_seria.errors, }, status=status.HTTP_400_BAD_REQUEST
)

总结:

  1. 将序列化与反序列化功能整合到一个类,这个类继承 ModelSerializer来实现

  2. 继承ModelSerializer类的资源序列化类内部包含三部分, Meta子类, 局部钩子、全局钩子

    • 注:create和update方法ModelSerializer已经重写了,使用不需要重写,默认不能实现群该功能,
    • 通过集成ListSerializer类update方法,实现群该功能,将其绑定给list_serializer_class
  3. 在Meta子类中:

    • 用model来绑定所关联的Model类
    • 用fields来设置所有的序列化反序列化字段
    • 用extra_kwargs来设置系统的校验规则
  4. 重要字段校验规则

    • read_only校验规则:代表该字段只参与序列化,不参与反序列化进行校验,就是校验数据传来了height这个参数,不会对数据进行校验只会返回原先的数据或者是默认的数据
    • write_only校验规则:只参与反序列化 设置这个就是在反序列化的时候不会返回给前台,不会序列化
    • required校验规则:代表该字段在反序列化,在数据库中有默认值或可以为空字段, required默认为false,前台发送的数据不会进行校验,只有为true时候才会进行校验
      • 如果一个字段有默认值或是可以为空,没设置required规则,默认为False,反之默认值为True
      • 如果一个Model字段即没有设置read_only也没设置write_only,该字段默认参与序列化及反序列化
  5. 自定义序列化字段:在Model类中,定义方法属性(可以返回特殊值,还可以完成连表操作),在序列化类的fields属性中可以选择性插拔(重要)自定义插拔序列化字段一定不参与反序列化过程

  6. 自定义反序列化字段:在Serializer类中,自定义校验字段,校验规则也只能在声明字段时设置,自定义的反序列化字段(如re_pwd),必须设置write_only为True 自定义插拔序列化字段一定不参与反序列化过程

  7. user_seria = UserModelSerializer(data=request_data),校验数据要将数据给data,才可以校验

  8. 在全局钩子中 一定要移除重复确认的字段

  9. 在反序列化的时候如果需要字段一定要传则在model中不给他设置默认值,一旦设置了默认值,反序列化的时候就可以不传值

  10. 使用fields来明确字段,__all__表名包含所有字段,也可以写明具体哪些字段,

  11. 使用exclude可以明确排除掉哪些字段

  12. 可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段

  13. 可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数

drf序列化和反序列化的更多相关文章

  1. drf序列化与反序列化

    序列化器-Serializer 定义序列化器 Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serial ...

  2. drf序列化及反序列化

    假如把drf看做一个汉堡包,我们之前讲的模块属于汉堡包前面的盖盖(请求模块.渲染模块)和底底(异常模块.解析模块.响应模块),但是真正中间的夹心没有讲,那么今天我就和大家来看一下汉堡包的夹心(序列化及 ...

  3. DRF序列化和反序列化(二:ModelSerializer)

    一: rest_framework 中 serializers.Serializer的不方便之处(以下简称Serializer) a:需要定义每一个字段,并且这个字段是和models字段及其类似. b ...

  4. drf序列化器与反序列化

    什么是序列化与反序列化 """ 序列化:对象转换为字符串用于传输 反序列化:字符串转换为对象用于使用 """ drf序列化与反序列化 &qu ...

  5. DRF框架(二)——解析模块(parsers)、异常模块(exception_handler)、响应模块(Response)、三大序列化组件介绍、Serializer组件(序列化与反序列化使用)

    解析模块 为什么要配置解析模块 1)drf给我们提供了多种解析数据包方式的解析类 form-data/urlencoded/json 2)我们可以通过配置来控制前台提交的哪些格式的数据后台在解析,哪些 ...

  6. drf的序列化和反序列化

    序列化器--Serializer 选项参数: max_length 最大长度 min_length 最小长度 allow_blank 是否允许为空 trim_whitespace 是否截断空白字符 m ...

  7. day71:drf:API接口&Restful API规范&Django Rest Framework&drf中的序列化和反序列化功能

    目录 1.web应用模式 2.API接口 3.Restful API规范 4.序列化 5.Django Rest Framework 1.drf的简单介绍 2.drf的特点 3.如何安装drf 4.d ...

  8. DRF框架(三)——media资源路径设置、多表设计复习及补充、序列化组件(ModelSerializer)操作多表(序列化与反序列化)、多表序列化与反序列化整合(重点)

    media资源路径设置  (设置好后把图片放在这个文件夹中,通过链接能访问到图片) 1.先在根目录设置一个media文件夹 2.配置settings.py,加上下面的 MEDIA_URL = '/me ...

  9. 前后端分离djangorestframework——序列化与反序列化数据

    我们写好后端的代码,要把数据交给前端的展示的,这个数据以什么类型给前端呢?学到这里,我们已经知道这个数据最好是json字符串才行,因为网络间的传输,只认字符串或者二进制,字符串就是我们的数据,二进制就 ...

随机推荐

  1. arduino双机通信 (解决引脚不够用)

    作用 实现将一个 arduino 中的多个 String 类型变量准确地传到另一个 arduino 中对应的多个 String 类型变量 中. 接线图 注意 TX 接另一个arduino的 RX !可 ...

  2. mui下拉刷新 上拉加载

    a页面是父页面   b页面是子页面 在b页 html+ js+ 下拉和上拉执行的函数就不贴了 .在这个过程中还遇到了个问题就是刷新的图标偏上 需要改变其高度,需要在a页面里面去改变刷新图标的样式 本文 ...

  3. IIS7实现访问HTTP定向至HTTPS访问

    工具及软件: 系统:windows2008R2 软件:IIS7.0,IIS的Microsoft URL重写模块2.0 下载 操作步骤: 1.下载并在IIS中安装Microsoft URL重写模块2.0 ...

  4. 查看 vps 进程网络流量

    弄好了 vps 以后,感觉网络流量走的有点多,决定查查看到底什么情况. 首先安装 sar 来看看各个设备消耗的流量 apt-get install sysstat sar 的参数 DEV 表示网口, ...

  5. Linux 正则表达式与文本处理器 三剑客

    Linux 正则表达式与文本处理器 三剑客 一.正则表达式 正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法.或者说:正则就是用来描述一类事物的规则. 在linu ...

  6. CodeForces - 131C The World is a Theatre(组合数)

    题意:已知有n个男生,m个女生.现在要选t个人,要求有至少4个男生,至少1个女生,求有多少种选法. 分析: 1.展开,将分子中的m!与分母中n!相约,即可推出函数C. #pragma comment( ...

  7. JZOJ-2019-11-5 A组

    T1 给定由 n 个点 m 条边组成的无向连通图,保证没有重边和自环. 你需要找出所有边,满足这些边恰好存在于一个简单环中.一个环被称为简单环,当且仅当它包含的所有点都只在这个环中被经过了一次.(即求 ...

  8. 直击JDD | 陈生强:京东数科的底层是数字化操作系统

    11月19日,由京东集团主办的JDD-2019京东全球科技探索者大会在京开幕,京东数字科技集团CEO陈生强作了题为"以科技为美,为价值而生"的主旨发言,再论"数字科技&q ...

  9. 吴裕雄--天生自然 JAVASCRIPT开发学习: 错误 - throw、try 和 catch

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  10. ftp主动和被动模式区别

    转载自:http://www.west999.com/cms/wiki/server/2018-11-16/49417.html FTP是基于TCP的服务的,FTP不同之处在于FTP使用两个端口,一个 ...