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>
pull/5377/head
fit2bot 2021-01-03 14:17:02 +08:00 committed by GitHub
parent 24b1c87121
commit 428e8bf2a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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):
""" 一个根据用户行为而动态匹配的字段 """