zoukankan      html  css  js  c++  java
  • Django REST framework之序列化组件以及源码分析+全局、局部Hook

    序列化两大功能

      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

  • 相关阅读:
    关于组建“智彩足球技术研究团队”的说明
    2次成功投诉EMS和中国移动的经验
    为什么选择玩足球彩票以及玩彩票的心态?
    【原创】机器学习之PageRank算法应用与C#实现(1)算法介绍
    【原创】开源Math.NET基础数学类库使用(17)C#计算矩阵条件数
    【原创】开源Math.NET基础数学类库使用(16)C#计算矩阵秩
    【文章】本站收集与转载文章目录
    【原创】.NET读写Excel工具Spire.Xls使用(3)单元格控制
    分享一个Visual Studio的背景插件,让堆码更富情趣
    【原创】开源Math.NET基础数学类库使用(15)C#计算矩阵行列式
  • 原文地址:https://www.cnblogs.com/Alexephor/p/11306201.html
Copyright © 2011-2022 走看看