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. mybatis今年笔记

    1.读取配置文件:用的就是解析Xml文件的技术 2.mybatis是支持自己写dao层的,但是没有必要. mybatis做的事情: 第一个创建代理对象,第二个在代理对象中调用方法. 3.相同的注解如果 ...

  2. vs2012(或2013)与虚拟机连调试

    一.安装Windows Driver Kit 8 1首先在计算机上安装VS2012 (12很容易安装,安装步骤略),然后到官网上下载Windows Driver Kit 8 下载地址: http:// ...

  3. GetqueueStatus

    #include "stdafx.h" #include <Windows.h> #include <process.h> #include <ios ...

  4. Egret Engine 2D - 显示容器

      DisplayObjectContainer 所有容器的父类 1 添加 删除 子对象 2 访问子对象 3 检测子对象 4 设置叠放次序 Sprite 继承自DisplayObjectContain ...

  5. bzoj 4300绝世好题

    呵呵呵呵 #include<bits/stdc++.h> #define INF 0x7fffffff #define LL long long #define N 100005 usin ...

  6. [Mathematics][Fundamentals of Complex Analysis][Small Trick] The Trick on drawing the picture of sin(z), for z in Complex Plane

    Exercises 3.2 21. (a). For $\omega = sinz$, what is the image of the semi-infinite strip $S_1 = \{x+ ...

  7. 使用openssl做CA服务器,并且生成证书。

    [root@22 conf.d]# openssl genrsa -out /etc/pki/CA/private/cakey.pem 4096  #ca私钥 [root@22 conf.d]# op ...

  8. Sequence Models Week 1 Improvise a Jazz Solo with an LSTM Network

    Improvise a Jazz Solo with an LSTM Network Welcome to your final programming assignment of this week ...

  9. HTTP协议(二):作用

    前言 上一节我们简单介绍了一下TCP/IP协议族的基本情况,知道了四大层的职责,也了解到我们这一族的家族成员以及他们的能力. 无良作者把我这个主角变成了配角,让我很不爽,好在我打了作者一顿,没错,这次 ...

  10. 自己组装一台1U服务器

    视频资料链接 自己组装一台1U服务器 执行思路: 1.评估访问了,根据需求确定服务器要求 2.根据要求选择硬件:冗余.稳定等 3.搜索主流服务器参数进行对比,及对比价格 4.咨询IDC机房价格 DIY ...