1225 drf序列化ModelSerializer序列化与反序列化
目录
Serializer类
底层序列化类 了解类
重点:单表序列化
ModelSerializer
模型序列化类 核心类
重点: 多表序列化
ListSerializer类
群操作序列化 辅助类
重点:辅助完成单表多表群增群改操作
drf序列化
1. django项目的设置
settings中配置
1.注册app以及rest_framework
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# drf中一定要注册才能使用
'rest_framework',
# 注册app
'api',
]
2.使用mysql数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'day72',
'USER':'root',
'PASSWORD':'',
}
}
import pymysql
pymysql.install_as_MySQLdb()
# 国际化配置
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False
# 静态文件配置
STATIC_URL = '/static/'
# 媒体文件配置
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
models.py配置
from django.db import models
# Create your models here.
from django.db import models
class User(models.Model):
# 配置sex的选项
SEX_CHOICES = (
(0,'女'),
(1,'男')
)
# verbose_name定义了admin显示表的字段名称,blank则可以在admin中可以空提交
username = models.CharField(max_length=64,verbose_name='用户名',blank=True)
password = models.CharField(max_length=64,verbose_name='密码')
sex = models.IntegerField(choices=SEX_CHOICES,default=0,verbose_name='性别')
icon = models.ImageField(upload_to='img',default='img/default.jpg',verbose_name='头像')
# 开发中,数据不会直接删除,通过字段控制
is_delete = models.BooleanField(default=False,verbose_name='是否注销')
# 数据库数据入库,一般都会记录该数据第一次入库时间,有时候还会记录最后一次更新事假
created_time = models.DateTimeField(auto_now_add=True,verbose_name='创建时间')
# 配置类,给所属的类提供配置信息
class Meta:
db_table = 'old_boy_user'
verbose_name_plural = '用户表'
# 不要在这里进行联表操作,比如admin页面会崩溃
def __str__(self):
return self.username
APP中的admin.py设置
from django.contrib import admin
# Register your models here.
from . import models
admin.site.register(models.User)
项目url.py
from django.conf.urls import url,include
from django.contrib import admin
# 设置django的media配置文件
from django.views.static import serve
from django.conf import settings
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/',include('api.urls')),
url(r'^media/(?P<path>.*)',serve,{'document_root':settings.MEDIA_ROOT})
]
三流(补充)
import sys
标准输出流
sys.stdout.write(123) # 会在控制台上打印123(不自动换行)
标准输入流
res = sys.stdin.readline() # 读取控制台上的数据
print(res)
标准错误流
sys.stderr.write('123/n') # 出现红色的打印信息
sys.stderr.write('123/n')
流的打印是异步的,但相同流之间的打印是同步的
2. 序列化
1. 自定义序列化过程
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from django.conf import settings
from . import models
class UserV1APIView(APIView):
# 单查群查
def get(self,request,*args,**kwargs):
pk = kwargs.get('pk')
if pk:
user_dic = models.User.objects.filter(is_delete=False,pk=pk).values('username','sex','icon').first()
if not user_dic:
return Response({
'status': 1,
'msg': 'pk error',
},status=400)
user_dic['icon'] = '%s%s%s' % (settings.BASE_URL,settings.MEDIA_URL,user_dic.get('icon'))
return Response({
'status':0,
'msg':'ok',
'results':user_dic
})
else:
user_query = models.User.objects.filter(is_delete=False).values('username','sex','icon')
for user_dic in user_query:
user_dic['icon'] = '%s%s%s' % (settings.BASE_URL,settings.MEDIA_URL,user_dic.get('icon'))
user_list = list(user_query)
return Response({
'status':0,
'msg':'ok',
'results':user_list
})
3. Serializer类
3.1 序列化过程
视图类序列化过程
1. orm操作得到数据
2. 将数据序列化成可以返回给前台的数据
3. 返回数据给前台
导入rest_framework的类serializers
-
字段名与字段类型要与处理的model类相对应
-
不提供的字段,就不参与序列化给前台
-
可以自定义序列化字段,采用方法序列化
方法固定两个参数,第二个参数就是参与序列化的model对象 严重不建议自定义字段名与数据库字段名重名,由get_'自定义字段名'方法的返回值提供字段值
序列化过程
--------------------------------------------------------
from . import serializers
class UserV2APIView(APIView):
# 单查群查
def get(self,request,*args,**kwargs):
pk = kwargs.get('pk')
if pk:
# 获取数据对象
user_obj = models.User.objects.filter(is_delete=False,pk=pk).first()
if not user_obj:
return Response({
'status': 1,
'msg': 'pk error',
},status=400)
# 交于视图类的序列化统一处理
user_ser = serializers.UserSerializers(user_obj,many=False) # many 默认为false
# 获取序列化返回的数据
user_obj_data = user_ser.data
return Response({
'status':0,
'msg':'ok',
'results':user_obj_data
})
else:
# 将对象对外提供的字段,以及整个序列化过程封装,形成序列化类
user_query = models.User.objects.filter(is_delete=False).all()
user_ser = serializers.UserSerializers(user_query,many=True)
# 将序列化后的所有数据返回出来,放在data中
user_list = user_ser.data
return Response({
'status':0,
'msg':'ok',
'results':user_list
})
--------------------------------------------------------
from django.conf import settings
# 导入rest_framework的类serializers
from rest_framework import serializers
class UserSerializers(serializers.Serializer):
# 1.字段名与字段类型要与处理的model类相对应
username = serializers.CharField()
# 2.不提供的字段, 就不参与序列化给前台
# sex = serializers.IntegerField()
# 3.可以自定义序列化字段, 采用方法序列化
gender = serializers.SerializerMethodField()
# 这里的obj就是传入的user对象
def get_gender(self,obj):
return obj.get_sex_display()
icon = serializers.SerializerMethodField()
# 在高级序列化与高级视图类中,drf默认帮我们处理图片等子资源的
def get_icon(self,obj):
return '%s%s%s' % (settings.BASE_URL, settings.MEDIA_URL, obj.icon)
序列化总结
- 设置序列化字段,字段名与字段类型要与处理的model类属性名对应(只参与序列化的类型不需要设置条件)
- model类中有的字段,但在序列化中没有对应字段,该类字段不参与序列化
- 自定义序列化字段(方法一),字段类型为SerializerMethodField(),值由
get_自定义字段名(self, model_obj)
方法提供,一般值都与参与序列化的model对象(model_obj)有关
3.2 反序列化
视图类反序列化过程
1. 从请求对象中获取前台提交的数据
2. 交给序列化类完成反序列化(数据的校验) 重要
3. 借助序列化类完成数据入库
4. 反馈给前台处理结果
# 单增
def post(self,request,*args,**kwargs):
# 用户输入的数据都在 request.data 中
request_data = request.data
# 反序列化必须使用data来指定
user_ser = serializers.UserDeSerializers(data=request_data)
# is_valid判断反序列化校验结果
if user_ser.is_valid():
# 入库,获取一个User对象
user_obj = user_ser.save()
return Response({
'status':0,
'msg':'ok',
# 这里利用序列化,将user_obj重新序列化返回data信息给前台
'results':serializers.UserSerializers(user_obj).data
})
else:
return Response({
'status':0,
'msg':'ok',
# 反序列化错误的信息都在.errors中(做了国际化)
'results':user_ser.errors
})
-------------------------------------------------------
from . import models
# 反序列化的类
class UserDeSerializers(serializers.Serializer):
# 系统校验字段(用于校验的表的属性)
# 不写,不参与反序列化,写就一定参与反序列化(但可以设置required=False取消必须)
# 反序列化的自定义校验信息
username = serializers.CharField(min_length=3,max_length=8,error_messages={
'min_length':'短',
'max_length':'长'
})
# 不需要定义报错信息也可以,国际化会自动提示
password = serializers.CharField(min_length=3,max_length=8)
# required = False控制字段可以不填写
sex = serializers.BooleanField(required=False)
# 自定义校验字段: 从设置语法与系统字段没有区别,但是这些字段不能参加入库操作,需要在全局钩子中将其取出
re_password = serializers.CharField(min_length=3, max_length=8)
# 局部钩子
# 方法名就是validate_校验的字段名(self,校验的字段数据)
# 校验规则:成功之后返回values,失败抛出校验失败信息
def validate_username(self,values):
if 'g' in values:
# 报错信息的添加在serializers.ValidationError中添加即可
raise serializers.ValidationError('名字中不能有g')
return values
# 全局钩子
# 方法名就是validate(self,所有的校验数据)
# 校验规则:成功之后返回attrs,失败抛出校验失败信息
def validate(self, attrs):
password = attrs.get('password')
re_password = attrs.pop('re_password')
if password != re_password:
raise serializers.ValidationError({'re_password':'两次密码不一致'})
return attrs
# 在视图类中调用序列化类的save方法完成入库,serializers类能做的:增入库走create方法,改入库走update方法
# 但serializers没有提供两个方法的实现体
def create(self, validated_data):
return models.User.objects.create(**validated_data)
# instance要被修改的对象,validated_data代表校验后用来改instance的数据
def update(self, instance: models.User, validated_data):
# 用户名不能被修改
validated_data.pop('username')
models.User.objects.filter(pk=instance.id).update(**validated_data)
return instance
反序列化总结
-
系统校验字段与自定义校验字段定义没有区别:
字段 = serializers.字段类型(条件)
-
自定义校验字段是不能直接入库的,需要设置入库规则,或将其移除不入库(这类字段就是参与全局校验用的)
-
所有字段都可以设置对应局部钩子进行校验
钩子方法 validate_字段名(self, 字段值value) 规则: 成功直接返回value,失败抛出校验失败信息ValidationError('错误信息')
-
一个序列化类存在一个全局钩子可以对所有字段进行全局校验
钩子方法 validate(self, 所有字段值字典attrs) 规则: 成功直接返回attrs,失败抛出校验失败信息ValidationError({'异常字段', '错误信息'})
-
重写create方法实现增入库,返回入库成功的对象
-
重写update方法实现改入库,返回入库成功的对象
4. ModelSerializer序列化
# 定义类并继承serializers.ModelSerializer
class 自定义名称(serializers.ModelSerializer):
class Meta:
model=对应的模型类
fields=('参与序列化和反序列的字段1','参与序列化和反序列的字段2')
extra_kwargs ={
参与序列化和反序列的字段1:{
'required': True, #必须填写的字段
# 约束条件
'min_length': 3,
# 报错信息
'error_messages': {
'min_length': '太短'
},
{
参与序列化和反序列的字段2:{
'write_only': True #只写, 反序列化
}
参与序列化和反序列的字段3:{
'read_only': True #只读, 序列化
}
}
}
使用代码
# 单增
def post(self,request,*args,**kwargs):
# 反序列直接将前台的数据传给类
user_ser = serializers.UserModelSerializers(data=request.data)
# is_valid判断反序列化校验结果
if user_ser.is_valid():
# 入库,获取一个User对象
user_obj = user_ser.save()
return Response({
'status':0,
'msg':'ok',
# 这里利用序列化,将user_obj重新序列化返回data信息给前台
'results':serializers.UserModelSerializers(user_obj).data
})
else:
return Response({
'status':0,
'msg':'ok',
# 反序列化错误的信息都在.errors中(做了国际化)
'results':user_ser.errors
})
--------------------------------------------------------
# 核心:单表序列化与反序列化操作
class UserModelSerializers(serializers.ModelSerializer):
# 1. 序列化
# 第一种自定义序列化字段:该字段必须在fields中设置
# gender = serializers.SerializerMethodField()
# def get_gender(self,obj):
# return obj.get_sex_display()
# 第二种,在models中定义 @property 方法
# @property
# def gender(self):
# return self.get_sex_display()
# 自定义反序列化字段同Serializer类,且规则只能在此声明中设置,或在钩子中设置,在extra_kwargs中设置无效
# 必须设置write_only
re_password = serializers.CharField(min_length=3,max_length=6)
# 系统字段
class Meta:
# 必须先绑定类
model = models.User
# fields采用"插拔式设计" 设置了参与序列化与反序列化的字段
fields = ('username','gender','icon','password','sex','re_password')
# 2.反序列化
# 如何将序列化与反序列化区分开
# 如何对反序列化字段进行校验
extra_kwargs = {
'username':{ # 系统字段,不设置only,默认都参加
# 自定义校验信息
'min_length':3,
'max_length':10,
'error_messages':{
'min_length': '短',
'max_length': '长',
}
},
'gender':{ # 自定义的序列化字段就是read_only,且不能修改,但可以省略
# 只参与序列化 'read_only':True
'read_only':True
},
'password':{
# 只参与反序列化 'write_only':True
'write_only':True
},
# 像sex有默认值的字段,为选填字段,'required':True将其变为必填字段
'sex':{
'write_only': True,
'required':True
}
}
# 局部钩子与全局钩子是与Meta同缩进的
# 局部钩子
def validate_username(self,values):
if 'g' in values:
raise serializers.ValidationError('名字中不能有g')
return values
# 全局钩子
def validate(self, attrs):
password = attrs.get('password')
re_password = attrs.pop('re_password')
if password != re_password:
raise serializers.ValidationError({'re_password':'两次密码不一致'})
return attrs
# create与update方法不要再重写,ModelSerializers类已经提供,且支持所有关系下的联表操作
序列化与反序列化总结
-
序列化类继承ModelSerializer,所以需要在配置类Meta中进行配置
-
model配置:绑定序列化相关的Model表
-
fields配置:采用 插拔式 设置所有参与序列化与反序列化字段
-
extra_kwargs配置:
划分系统字段为三种: 只读(read_only)、只写(write_only)、可读可写(不设置) 字段是否必须: 'required':True将其变为必填字段 选填字段: 在extra_kwargs进行配置,但不设置required,且有默认值
-
-
自定义序列化字段:
* 第一种(不提倡): # 该字段必须在fields中设置 gender = serializers.SerializerMethodField() def get_gender(self,obj): return obj.get_sex_display() * 第二种(提倡): # 在模型类中用@property来实现,可插拔 @property def gender(self): return self.get_sex_display()
-
自定义反序列化字段:
同Serializer类,且规则只能在此声明中设置,或是在钩子中设置,在extra_kwargs中对其设置的无效 自定义反序列化字段与系统字段,设置规则一样,所以必须设置 write_only
-
局部钩子,全局钩子同Serializer类
-
不需要重写create和update方法