perf: 修改 View dynamic mapping include dynamic mapping fields Serializer Class 方案的说明 (#5373)

* perf: 修改 View dynamic mapping `include dynamic mapping fields Serializer Class` 方案的说明

* perf: 修改 View dynamic mapping `include dynamic mapping fields Serializer Class` 方案的说明 (2)

Co-authored-by: Bai <bugatti_it@163.com>
This commit is contained in:
fit2bot
2021-01-03 14:17:02 +08:00
committed by GitHub
parent 24b1c87121
commit 428e8bf2a0
2 changed files with 36 additions and 16 deletions

View File

@@ -3,8 +3,10 @@
View 获取 serializer_class 的架构设计
问题:
View 所需的 Serializer 中有一个 JSONField 字段,字段的并不固定,是由 View 的行为 (比如action) 而决定的.
使用 View 默认的 get_serializer_class 方法不能解决
View 所需的 Serializer Class 中有一个字段,字段的类型并不固定,
而是由 View 的行为 (比如 type, action) 来决定的.
使用 View 默认的 get_serializer_class 方法不能实现,因为序列类在被定义的时候,其字段及类型已经固定,
所以需要一种机制来动态修改序列类中的字段及其类型MetaClass 元类
例如:
@@ -19,33 +21,49 @@
class Serializer(serializers.Serializer):
meta = serializers.JSONField()
当 view 获取 serializer 时无论action时什么获取到的 Serializer.meta 是 serializers.JSONField(),
当 view 获取 serializer 时,无论 action 是什么, 获取到的 Serializer.meta 字段始终
serializers.JSONField() 类型
但我们希望:
当 view.action = A 时,获取到的 Serializer.meta 是 MetaASerializerMetaASerializer()
当 view.action = B 时,获取到的 Serializer.meta 是 MetaBSerializerMetaASerializer()
分析:
问题关键在于数据映射
使用 dict 可以解决,但操作起来比较复杂
所以使用 tree 的结构来实现
问题关键在于数据映射规则的定义和匹配,
即, 用 View 给定的规则动态去匹配 Serializer Class 中定义的规则, 从而创建出想要的序列类
当然, 使用 dict 可以很好的解决规则定义问题,但要直接进行匹配, 操作起来比较复杂
所以, 决定使用以下方案实现, 即, dict, dict-> tree 数据类型转化, tree 搜索:
Serializer Class 中规则的定义使用 dict,
View 中指定的规则也使用 dict,
MetaClass 中进行规则匹配的过程使用 dict tree, 即将给定的 dic 转换为 tree 的数据结构,再进行匹配,
* dict -> tree 的转化使用 `data-tree` 库来实现
方案:
view:
使用元类 MetaClass: 在 View 中动态创建所需要的 Serializer
使用元类 MetaClass: 在 View 中动态创建所需要的 Serializer Class
serializer:
实现 DictSerializer: 在 Serializer 中定义 JSONField 字段的映射关系
实现 TreeSerializer: 将 DictSerializer 中定义的映射关系转换为 Tree 的结构
实现 DictSerializerMetaClass: 在 View 中用来动态创建 Serializer
实现 DynamicMappingField: 序列类的动态映射字段, 用来定义字段的映射规则
实现 IncludeDynamicMappingFieldSerializerMetaClass:
在 View 中用来动态创建 Serializer Class.
即, 用 View 中给定的规则,去匹配 Serializer Class 里每一个 DynamicMappingField 字段定义的规则,
基于 bases, 创建并返回新的 Serializer Class
实现 IncludeDynamicMappingFieldSerializerViewMixin:
实现动态创建 Serializer Class 的逻辑,
同时定义获取 Serializer Class 中所有 DynamicMappingField 字段匹配规则的方法
=>
def get_dynamic_mapping_fields_mapping_rule(self):
return {
'dynamic_mapping_field_name1': `mapping_path`,
'dynamic_mapping_field_name2': `mapping_path',
}
供 View 子类重写
实现:
1. 重写 View 的 get_serializer_class 方法, 实现动态创建 Serializer
2. 实现 TreeSerializer, 将 DictSerializer 中的 dict 数据结构转化为 tree 的数据结构
3. 实现 DictSerializer, 使用 dict 类型来定义映射关系 (*注意: 继承 TreeSerializer)
4. 实现 DictSerializerMetaClass, 定义如何创建包含字段类型为 TreeSerializer 的 Serializer
请看 ./serializer.py 和 ./serializer.py
"""
from rest_framework.serializers import Serializer

View File

@@ -1,3 +1,4 @@
import copy
import data_tree
from rest_framework import serializers
@@ -126,6 +127,7 @@ class IncludeDynamicMappingFieldSerializerMetaClass(serializers.SerializerMetacl
# DynamicMappingField
# ----------------------------------
class DynamicMappingField(serializers.Field):
""" 一个根据用户行为而动态匹配的字段 """