table of Contents
Serializer class
underlying sequence of classes in the class
Key: single table serialized
ModelSerializer
model serialization class core classes
focus on: the sequence of multi-table
ListSerializer type
sequence of operations of the group of auxiliary class
Key: Auxiliary multi-table group to complete a single table change operation by group
drf serialization
1. django project settings
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 Configuration
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 is set admin.py
from django.contrib import admin
# Register your models here.
from . import models
admin.site.register(models.User)
Project 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})
]
Third-rate (supplement)
import sys
标准输出流
sys.stdout.write(123) # 会在控制台上打印123(不自动换行)
标准输入流
res = sys.stdin.readline() # 读取控制台上的数据
print(res)
标准错误流
sys.stderr.write('123/n') # 出现红色的打印信息
sys.stderr.write('123/n')
流的打印是异步的,但相同流之间的打印是同步的
2. Serialization
1. custom serialization process
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 class
3.1 serialization process
视图类序列化过程
1. orm操作得到数据
2. 将数据序列化成可以返回给前台的数据
3. 返回数据给前台
Introducing the class serializers rest_framework
Field name field type to be treated with the corresponding model class
Field is not provided, do not participate in the serialization to the front
Fields can be custom serialization, serialization method
方法固定两个参数,第二个参数就是参与序列化的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)
Serialization summary
- Set serializable fields, field names and field types for a process model corresponding to the class name attribute (type need not only participate in serialization setting conditions)
- Some model class field, but not in the sequence of the corresponding field, such fields do not participate serialized
- Custom serialization field (a method), the type field is SerializerMethodField (), the value of the
get_自定义字段名(self, model_obj)
provided methods, typical values are related to the object model of the sequences which are involved (model_obj)
3.2 deserialization
视图类反序列化过程
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
Deserialization summary
Check field system with a custom check field definitions no difference:
字段 = serializers.字段类型(条件)
Custom check field is not directly warehousing, storage rules need to set or remove without storage (such field is used to participate in a global parity)
All fields are set corresponding local checksum hook
钩子方法 validate_字段名(self, 字段值value) 规则: 成功直接返回value,失败抛出校验失败信息ValidationError('错误信息')
Existence of a sequence of a global hook can check all fields globally
钩子方法 validate(self, 所有字段值字典attrs) 规则: 成功直接返回attrs,失败抛出校验失败信息ValidationError({'异常字段', '错误信息'})
Rewrite the create method to achieve increased storage, warehousing successful return of objects
Rewrite the update method to achieve change in storage, warehousing successful return of objects
4. ModelSerializer serialized
# 定义类并继承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 #只读, 序列化
}
}
}
Using the code
# 单增
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类已经提供,且支持所有关系下的联表操作
Serialization and de-serialization summary
Serialization class inheritance ModelSerializer, it needs to be configured in the configuration class Meta
Configuration model: Model binding sequence of related tables
configuration fields: The plug provided all participating deserialization and serialization field
extra_kwargs configuration:
划分系统字段为三种: 只读(read_only)、只写(write_only)、可读可写(不设置) 字段是否必须: 'required':True将其变为必填字段 选填字段: 在extra_kwargs进行配置,但不设置required,且有默认值
Custom serialization fields:
* 第一种(不提倡): # 该字段必须在fields中设置 gender = serializers.SerializerMethodField() def get_gender(self,obj): return obj.get_sex_display() * 第二种(提倡): # 在模型类中用@property来实现,可插拔 @property def gender(self): return self.get_sex_display()
Custom deserialization fields:
同Serializer类,且规则只能在此声明中设置,或是在钩子中设置,在extra_kwargs中对其设置的无效 自定义反序列化字段与系统字段,设置规则一样,所以必须设置 write_only
Local hooks, hooks with the global class Serializer
You do not need to rewrite the create and update methods