序列化两大功能
a.对queryset类型进行序列化
b.对用户请求的数据进行校验
a.对queryset类型进行序列化
举例说明:
表设计
1 from django.db import models 2 3 4 class UserGroup(models.Model): 5 title = models.CharField(max_length=32) 6 7 8 class UserInfo(models.Model): 9 user_type_choices = ( 10 (1, '普通用户'), 11 (2, 'vip'), 12 (3, 'svip'), 13 ) 14 user_type = models.IntegerField(choices=user_type_choices) 15 username = models.CharField(max_length=32, unique=True) 16 password = models.CharField(max_length=64) 17 group = models.ForeignKey('UserGroup', on_delete=models.CASCADE) 18 roles = models.ManyToManyField('Role') 19 20 21 class UserToken(models.Model): 22 user = models.OneToOneField(to='UserInfo', on_delete=models.CASCADE) 23 token = models.CharField(max_length=64) 24 25 26 class Role(models.Model): 27 title = models.CharField(max_length=32)
总路由:
1 from django.contrib import admin 2 from django.urls import path, re_path, include 3 4 urlpatterns = [ 5 path('admin/', admin.site.urls), 6 re_path('api/', include('api.urls')), 7 ]
分发:
#!/usr/bin/env python # -*- coding:utf-8 -*- from django.urls import path, re_path, include from api import views urlpatterns = [ # 序列化 re_path('(?P<version>[v1|v2]+)/roles/$', views.RolesView.as_view()), re_path('(?P<version>[v1|v2]+)/userinfo/$', views.UserInfoView.as_view()), # 序列化并生成url查看详情restful返回链接 re_path('(?P<version>[v1|v2]+)/group/(?P<pk>\d+)$', views.GroupView.as_view(), name='group'), # 验证 re_path('(?P<version>[v1|v2]+)/usergroup/$', views.UserGroupView.as_view()), ]
视图初探 继承serializers.Serializer 版本1 字段初探
1 import json 2 from django.shortcuts import render, HttpResponse 3 from rest_framework import serializers 4 from api import models 5 6 7 class RolesSerializer(serializers.Serializer): 8 id = serializers.IntegerField() 9 title = serializers.CharField() 10 11 12 class RolesView(APIView): 13 14 def get(self, request, *args, **kwargs): 15 # 方式1 16 # roles = models.Role.objects.all().values('id', 'title') 17 # roles = list(roles) 18 # ret = json.dumps(roles, ensure_ascii=False) 19 # 方式2 20 # roles = models.Role.objects.all() 21 # ser = RolesSerializer(instance=roles, many=True) 22 # ret = json.dumps(ser.data, ensure_ascii=False) 23 24 role = models.Role.objects.all().first() 25 ser = RolesSerializer(instance=role, many=False) 26 ret = json.dumps(ser.data, ensure_ascii=False) 27 return HttpResponse(ret)
继承serializers.Serializer 版本2 进阶对序列类字段着手
1 class UserInfoSerializer(serializers.Serializer): 2 # user_type = serializers.IntegerField() 3 uuu = serializers.CharField(source='user_type') 4 # 显示用户类型get_user_type_display内部是否callable若能直接调用,不能就直接返回 5 ooo = serializers.CharField(source='get_user_type_display') 6 username = serializers.CharField() 7 password = serializers.CharField() 8 # 显示用户组名称 9 gp = serializers.CharField(source='group.title') 10 # 显示用户在的所有组 11 # roles = serializers.CharField(source='roles.all') # 力度不够 12 # 处理ManyToManyField字段 13 role = serializers.SerializerMethodField() 14 15 def get_role(self, row): 16 role_obj_list = row.roles.all() 17 ret = [] 18 for item in role_obj_list: 19 ret.append({'id': item.id, 'title': item.title}) 20 return ret
继承serializers.ModelSerializer 版本3 对字段着手
1 class UserInfoSerializer(serializers.ModelSerializer): 2 ooo = serializers.CharField(source='get_user_type_display') 3 # Serializer(BaseSerializer, metaclass=SerializerMetaclass) 4 # ModelSerializer(Serializer) 5 role = serializers.SerializerMethodField() 6 7 class Meta: 8 model = models.UserInfo 9 # fields = '__all__' 10 fields = ['id', 'username', 'password', 'ooo', 'role', 'group'] 11 12 def get_role(self, row): 13 role_obj_list = row.roles.all() 14 ret = [] 15 for item in role_obj_list: 16 ret.append({'id': item.id, 'title': item.title}) 17 return ret
深度自动连表操作
1 class UserInfoSerializer(serializers.ModelSerializer): 2 # ooo = serializers.CharField(source='get_user_type_display') 3 # Serializer(BaseSerializer, metaclass=SerializerMetaclass) 4 # ModelSerializer(Serializer) 5 6 class Meta: 7 model = models.UserInfo 8 fields = '__all__' 9 depth = 1 # 官方0~10 自我感觉最多2层,层数多响应数据慢
返回json数据中给用户提供链接字段
1 class UserInfoSerializer(serializers.ModelSerializer): 2 # ooo = serializers.CharField(source='get_user_type_display') 3 # Serializer(BaseSerializer, metaclass=SerializerMetaclass) 4 # ModelSerializer(Serializer) 5 # 生成url查看用户组详情链接restful规范在实例化时候必须加上context={'request': request}字段 6 group = serializers.HyperlinkedIdentityField(view_name='group', lookup_field='group_id', lookup_url_kwarg='pk') 7 8 class Meta: 9 model = models.UserInfo 10 fields = '__all__' 11 depth = 1 # 官方0~10 自我感觉最多2层倒是行了 12 13 14 class UserInfoView(APIView): 15 def get(self, request, *args, **kwargs): 16 """ 17 取数据序列化 18 :param request: 19 :param args: 20 :param kwargs: 21 :return: 22 """ 23 users = models.UserInfo.objects.all() 24 ser = UserInfoSerializer(instance=users, many=True, context={'request': request}) 25 ret = json.dumps(ser.data, ensure_ascii=False) 26 return HttpResponse(ret)
在页面显示提供url链接地址
1 class GroupSerializer(serializers.ModelSerializer): 2 class Meta: 3 model = models.UserGroup 4 fields = '__all__' 5 6 7 class GroupView(APIView): 8 def get(self, request, *args, **kwargs): 9 pk = kwargs.get('pk') 10 obj = models.UserGroup.objects.filter(pk=pk).first() 11 ser = GroupSerializer(instance=obj, many=False) 12 return HttpResponse(json.dumps(ser.data, ensure_ascii=False))
b.对用户请求数据进行校验
自定义验证规则validators+钩子
1 class XValidator(object): 2 def __init__(self, base): 3 self.base = base 4 5 def __call__(self, value): 6 if not value.startswith(self.base): 7 message = '必须以%s 开头' % self.base 8 raise serializers.ValidationError(message) 9 10 def set_context(self, serializer_field): 11 """ 12 This hook is called by the serializer instance, 13 prior to the validation call being made. 14 """ 15 # 执行验证之前调用,serializer_fields是当前字段对象 16 pass 17 18 19 class UserGroupSerializer(serializers.Serializer): 20 title = serializers.CharField(error_messages={'required': '不能为空'}, validators=[XValidator('字母或者下划线'), ]) 21 # 局部钩子 22 23 def validate_title(self, value): 24 from rest_framework.exceptions import ValidationError 25 print(value) 26 # raise ValidationError('仇恨有点大,不让你通过') 27 return value 28 # 全局钩子 29 30 def validate(self, attrs): 31 print(attrs) 32 return attrs 33 34 35 class UserGroupView(APIView): 36 def post(self, request, *args, **kwargs): 37 ser = UserGroupSerializer(data=request.data) 38 if ser.is_valid(): 39 print(ser.validated_data['title']) 40 else: 41 print(ser.errors) 42 43 return HttpResponse('提交数据')
序列化源码分析+钩子源码分析
分析之前熟知继承关系:ModelSerializer--->Serializer--->BaseSerializer, metaclass=SerializerMetaclass
序列化分析:
ModelSerializer--->Serializer--->BaseSerializer--->__new__(1.many=True,执行many_init生成ListSerializer对象;2many=False生成Serializer对象)---->序列化对象.data方法----->调父类super().data方法----->调用对象自己的self.to_representation对象(自己定义的序列化类里边没有,就走ModelSerializer里边找,里边也没有,在进一层Serializer)------------>Serializer类的(to_representation方法)---->for循环每个字段对象attribute = field.get_attribute(instance)--->返回get_attribute(instance, self.source_attrs)其中在这里instance就是queryset对象,self.source_attrs就是分割替换赋值等处理之后的source,当做参数传进去,判断是否可callable,是直接加括号执行,是数据属性就提取出来。
Hook函数:
局部钩子:is_valid--->self.run_validation(self.initial_data)---注意--->(serializer类的run_validation)--->to_internal_value(两个有序字典ret, errors)--->循环fiels--->钩子函数(字符串拼接,通过反射取出我们定义的钩子函数)抛错必须抛ValidationError
全局钩子:就在局部钩子下面在530行 返回attrs