python - 在 Django 中初始化时拦截和替换序列化器字段
问题描述
所以我有一个带有大量模型的 Django REST 框架的 Django 项目。为了使前端用户友好,我不仅应该显示相关对象的 ID,还应该显示名称。我对解决方案的想法是在响应时用序列化程序中的 StringRelatedFields 替换所有 PrimaryKeyRelated 字段。由于模型的数量很大,我决定制作一个抽象的序列化器/mixin 并拦截字段创建,如果类型正确,则替换该字段。这是我到现在为止的距离:
class AbstractSerializer(serializers.ModelSerializer):
class Meta:
model: AbstractModel = AbstractModel
read_only_fields: list = [
'created_at',
'created_by',
'modified_at',
'modified_by',
'is_deleted',
'deleted_at',
'deleted_by'
] + ['is_active'] if 'is_active' in [field.attname for field in model._meta.fields] else []
abstract: bool = True
def to_representation(self, instance):
serializer = AbstractRequestResponseSerializer(instance)
return serializer.data
class AbstractRequestResponseSerializer(AbstractSerializer):
class Meta(AbstractSerializer.Meta):
pass
@classmethod
def _get_declared_fields(cls, bases, attrs):
fields = [(field_name, attrs.pop(field_name))
for field_name, obj in list(attrs.items())
if isinstance(obj, Field)]
fields.sort(key=lambda x: x[1]._creation_counter)
new_fields = []
for field in fields:
if isinstance(field, PrimaryKeyRelatedField):
field = StringRelatedField(source=field.source, required=False)
new_fields.append(field)
fields = new_fields
known = set(attrs)
def visit(name):
known.add(name)
return name
base_fields = [
(visit(name), f)
for base in bases if hasattr(base, '_declared_fields')
for name, f in base._declared_fields.items() if name not in known
]
return OrderedDict(base_fields + fields)
由于方法的原因,这会产生无限循环错误__new__
,我开始怀疑我是否覆盖了正确的函数。我也尝试替换to_representation
函数,但我猜当所有字段实例都已创建时,该函数在流程中出现得太晚了。我应该覆盖哪个功能?
解决方案
也许我错误地表述了这个问题(你可以重新表述以帮助后代:)),但我提出的解决方案如下所示:
class AbstractSerializer(serializers.ModelSerializer):
class Meta:
model: AbstractModel = AbstractModel
read_only_fields: list = [
'created_at',
'created_by',
'modified_at',
'modified_by',
'is_deleted',
'deleted_at',
'deleted_by'
] + ['is_active'] if 'is_active' in [field.attname for field in model._meta.fields] else []
abstract: bool = True
def to_representation(self, instance):
ret = OrderedDict()
fields = self._readable_fields
for field in fields:
if isinstance(field, PrimaryKeyRelatedField):
parent = field.parent
field_name = field.field_name
source = field.source
if source != field_name:
field = StringRelatedField(source=field.source, required=False)
else:
field = StringRelatedField(required=False)
field.bind(field_name, parent)
try:
attribute = field.get_attribute(instance)
except SkipField:
continue
check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
if check_for_none is None:
ret[field.field_name] = None
else:
ret[field.field_name] = field.to_representation(attribute)
return ret
推荐阅读
- python - NumPy 数组花式索引
- vba - 用于表中自动列检测的 Vba 脚本
- r - 如何更改不同语言环境中的字母?
- react-native - 我如何在“React-Native”中实现“ONVIF”协议?
- mysql - mysql - 使用 union all 查询 3 个数据库 - 优化
- quasar-framework - Quasar:从按钮中删除阴影
- c - 在不使用 pow() 和使用 While 循环的情况下创建一个程序来求解幂:“未定义”答案的问题
- php - PHP mysql - mysql 中使用的空 php 变量选择所有行
- ios - Swift 4 移动 UIButton 的位置
- python - python中特定时间段的重采样问题