1. 序列化基本使用
数据准备:
models.py:
from django.db import models
class UserInfo(models.Model):
user_type_choices = (
(1, '普通用户'),
(2, 'VIP用户'),
(3, 'SVIP用户'),
)
user_type = models.IntegerField(choices=user_type_choices)
name = models.CharField(max_length=32, unique=True)
pwd = models.CharField(max_length=64)
user_group = models.ForeignKey('UserGroup', on_delete=models.CASCADE)
role = models.ManyToManyField('Role')
class Token(models.Model):
user_info = models.OneToOneField(to='UserInfo', on_delete=models.CASCADE)
token = models.CharField(max_length=64)
class UserGroup(models.Model):
title = models.CharField(max_length=32)
class Role(models.Model):
title = models.CharField(max_length=32)
生成的数据表:
在角色表中添加如下数据:
原先使用 json.dumps
方法对从数据库中获取到的数据进行序列化:
urls.py:
from django.urls import path, re_path
from . import views
urlpatterns = [
re_path('(?P<version>[v1,v2]+)/roles/', views.RolesView.as_view()),
]
views.py:
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
class RolesView(APIView):
def get(self, request, *args, **kwargs):
roles = models.Role.objects.all()
print(roles) # <QuerySet [<Role: Role object (1)>, <Role: Role object (2)>]>
roles = models.Role.objects.all().values('id', 'title')
print(roles) # <QuerySet [{'id': 1, 'title': '管理员'}, {'id': 2, 'title': '超级管理员'}]>
roles = list(roles) # [<Role: Role object (1)>, <Role: Role object (2)>]
print(roles) # [{'id': 1, 'title': '管理员'}, {'id': 2, 'title': '超级管理员'}]
ret = json.dumps(roles, ensure_ascii=False)
return HttpResponse(ret)
现在我们可以使用Django REST framework中的序列化来对从数据库中的获取的数据进行序列化:
views.py:
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
from rest_framework import serializers
class MySerializers(serializers.Serializer):
"""
自定义序列化类
"""
id = serializers.IntegerField()
title = serializers.CharField()
class RolesView(APIView):
def get(self, request, *args, **kwargs):
roles = models.Role.objects.all()
# 因为对象不止一个,序列化[obj,obj,obj]这种,要使用many=True
serializers = MySerializers(instance=roles, many=True)
print(serializers)
"""
MySerializers(instance=<QuerySet [<Role: Role object (1)>, <Role: Role object (2)>]>, many=True):
id = IntegerField()
title = CharField()
"""
# serializers.data是已经转换完成的结果
print(serializers.data) # [OrderedDict([('id', 1), ('title', '管理员')]), OrderedDict([('id', 2), ('title', '超级管理员')])]
ret = json.dumps(serializers.data, ensure_ascii=False)
return HttpResponse(ret)
对于从数据库中获取一条数据,如果适用序列化:
views.py:
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
from rest_framework import serializers
class MySerializers(serializers.Serializer):
"""
自定义序列化类
"""
id = serializers.IntegerField()
title = serializers.CharField()
class RolesView(APIView):
def get(self, request, *args, **kwargs):
roles = models.Role.objects.first()
# 因为就一个对象,序列化obj,要使用many=False
serializers = MySerializers(instance=roles, many=False) # 默认也是False
print(serializers)
"""
MySerializers(instance=<Role: Role object (1)>):
id = IntegerField()
title = CharField()
"""
print(serializers.data) # {'id': 1, 'title': '管理员'}
# serializers.data是已经转换完成的结果
ret = json.dumps(serializers.data, ensure_ascii=False)
return HttpResponse(ret)
2. 自定义字段
Django REST framework的序列化可以允许我们自定义字段,从数据库中获取字段值也特别方便:
from django.urls import path, re_path
from . import views
urlpatterns = [
re_path('(?P<version>[v1,v2]+)/userinfo/', views.UserinfoView.as_view()),
]
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
from rest_framework import serializers
class UserinfoSerializer(serializers.Serializer):
username = serializers.CharField()
pwd = serializers.CharField()
user_type_id = serializers.CharField(source='user_type') # source对应数据库中字段,row.user_type
user_type_title = serializers.CharField(source='get_user_type_display') # row.get_user_type_display()
group_title = serializers.CharField(source='user_group.title')
rls = serializers.SerializerMethodField() # 自定义展示
def get_rls(self, row):
row_obj_list = row.role.all()
ret = []
for item in row_obj_list:
ret.append({'id': item.id, 'title': item.title})
return ret
class UserinfoView(APIView):
def get(self, request, *args, **kwargs):
userinfo = models.UserInfo.objects.all()
userinfo_serializer = UserinfoSerializer(userinfo, many=True)
ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
return HttpResponse(f"{ret}")
3. ModelSerializer
ModelSerializer类继承了Serializer,内部做了一些操作可以自动生成所有的字段:
class UserinfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class UserinfoView(APIView):
def get(self, request, *args, **kwargs):
userinfo = models.UserInfo.objects.all()
userinfo_serializer = UserinfoSerializer(userinfo, many=True)
ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
return HttpResponse(f"{ret}")
简单的可以直接用数据库的字段适用ModelSerializer生成,复杂的可以自定义:
class UserinfoSerializer(serializers.ModelSerializer):
user_type_title = serializers.CharField(source='get_user_type_display')
group_title = serializers.CharField(source='user_group.title')
rls = serializers.SerializerMethodField()
class Meta:
model = models.UserInfo
# fields = "__all__"
fields = ['id', 'username', 'pwd', 'rls', 'user_type_title', 'group_title',]
def get_rls(self, row):
row_obj_list = row.role.all()
ret = []
for item in row_obj_list:
ret.append({'id': item.id, 'title': item.title})
return ret
class UserinfoView(APIView):
def get(self, request, *args, **kwargs):
userinfo = models.UserInfo.objects.all()
userinfo_serializer = UserinfoSerializer(userinfo, many=True)
ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
return HttpResponse(f"{ret}")
生成字段的时候可以额外加一些参数,可以不用再定义group_title:
class UserinfoSerializer(serializers.ModelSerializer):
user_type_title = serializers.CharField(source='get_user_type_display')
# group_title = serializers.CharField(source='user_group.title')
rls = serializers.SerializerMethodField()
class Meta:
model = models.UserInfo
# fields = "__all__"
fields = ['id', 'username', 'pwd', 'rls', 'user_type_title', ]
extra_kwargs = {'group_title': {'source': 'user_group.title'}} # 和上面自定义一样
def get_rls(self, row):
row_obj_list = row.role.all()
ret = []
for item in row_obj_list:
ret.append({'id': item.id, 'title': item.title})
return ret
class UserinfoView(APIView):
def get(self, request, *args, **kwargs):
userinfo = models.UserInfo.objects.all()
userinfo_serializer = UserinfoSerializer(userinfo, many=True)
ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
return HttpResponse(f"{ret}")
4. 深度控制
只需要在Meta中设置 depth
字段就可以 自动序列化连表 获取关联表中的字段:
class UserinfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
"""
depth:0~10,0表示只获取UserInfo中的表中的字段的值
"""
depth = 1
class UserinfoView(APIView):
def get(self, request, *args, **kwargs):
userinfo = models.UserInfo.objects.all()
userinfo_serializer = UserinfoSerializer(userinfo, many=True)
ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
return HttpResponse(f"{ret}")
class UserinfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = ['id', 'username', 'pwd', 'user_type', 'user_group', 'role']
depth = 1
5. 生成链接
Django REST framework中的序列化也可以帮助我们生成超链接:
urls.py:
from django.urls import path, re_path
from . import views
urlpatterns = [
re_path('(?P<version>[v1,v2]+)/userinfo/', views.UserinfoView.as_view()),
re_path('(?P<version>[v1,v2]+)/group/(?P<pk>\d+)', views.GroupView.as_view(), name='gp'),
]
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
from rest_framework import serializers
class UserinfoSerializer(serializers.ModelSerializer):
group = serializers.HyperlinkedIdentityField(view_name='gp', lookup_url_kwarg='pk',
lookup_field='user_group_id') # pk和url上自定义的pk有关系
class Meta:
model = models.UserInfo
fields = ['id', 'username', 'pwd', 'user_type', 'user_group', 'role', 'group']
depth = 1
class UserinfoView(APIView):
def get(self, request, *args, **kwargs):
userinfo = models.UserInfo.objects.all()
userinfo_serializer = UserinfoSerializer(userinfo, many=True, context={'request': request})
ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
return HttpResponse(f"{ret}")
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserGroup
fields = '__all__'
class GroupView(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk') # url传过来的pk对应/(?P<version>[v1,v2]+)/group/(?P<pk>\d+)/
obj = models.UserGroup.objects.filter(pk=pk).first()
group_serializer = GroupSerializer(instance=obj, many=False)
ret = json.dumps(group_serializer.data, ensure_ascii=False)
return HttpResponse(f"{ret}")
6. 请求数据校验
Django REST framework序列化还可以做 请求数据校验
,简单的数据校验:
class UserGroupSerializer(serializers.Serializer):
# title = serializers.CharField(error_messages={'required':'dsdsd'})#error_messages暂时没作用
# 写需要校验的字段
title = serializers.CharField()
class UserGroupView(APIView):
def post(self, request, *args, **kwargs):
print(request.data) # {'title': ''}
ser = UserGroupSerializer(data=request.data)
if not ser.is_valid():
print(
ser.errors['title'][0]) # {'title': [ErrorDetail(string='This field may not be blank.', code='blank')]}
else:
print(ser.validated_data,
type(ser.validated_data)) # OrderedDict([('title', '3组')]) <class 'collections.OrderedDict'>
print(ser.validated_data['title']) # 3组
return HttpResponse()
7. 自定义验证规则
简单的数据校验一般不能满足需求,很多情况下需要自定义验证规则校验数据:
class UserGroupValidator:
def __init__(self, base):
self.base = str(base)
def __call__(self, value):
"""数据一提交过来就会执行这个__call__方法"""
print('提交过来title的值', value) # value是提交过来的值
if not value.endswith(self.base):
message = '标题必须以%s结尾!' % self.base
raise serializers.ValidationError(message)
def set_context(self, serializer_field):
"""执行验证之前调用,serializer_field是当前字段对象,这里用不到"""
pass
class UserGroupSerializer(serializers.Serializer):
title = serializers.CharField(validators=[UserGroupValidator('组'), ])
class UserGroupView(APIView):
def post(self, request, *args, **kwargs):
# print(request.data) # {'title': '3'}
ser = UserGroupSerializer(data=request.data)
if not ser.is_valid():
print(
ser.errors['title'][0]) # {'title': [ErrorDetail(string='This field may not be blank.', code='blank')]}
else:
print(ser.validated_data,
type(ser.validated_data)) # OrderedDict([('title', '3组')]) <class 'collections.OrderedDict'>
print(ser.validated_data['title']) # 3组
return HttpResponse()
自定义验证规则时,需要用到钩子函数,需要从 is_valid
方法开始找。