在Django初始化时拦截并替换序列化器字段



所以我有一个带有大量模型的Django REST框架的Django项目。对于前端是用户友好的,我不仅应该显示相关对象的id,还应该显示名称。我对解决方案的想法是将响应序列化器中的所有PrimaryKeyRelated字段替换为StringRelatedFields。由于模型的数量很大,我决定制作一个抽象序列化器/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 ParentModelSerializer(serializers.ModelSerializer):
class Meta:
model = ParentModel
fields = '__all__'
class ChildModelSerializer(serializers.ModelSerializer):
parent = ParentModelSerializer(read_only=True)
class Meta:
model = ChildModel
fields = '__all__'

或者如果你想在父元素中显示子元素:

class ParentModelSerializer(serializers.ModelSerializer):
children = ChildModelSerializer(read_only=True, many=True)
# children is the "related_name"
class Meta:
model = ParentModel
fields = '__all__'
class ChildModelSerializer(serializers.ModelSerializer):
class Meta:
model = ChildModel
fields = '__all__'

也许我的问题措辞不正确(你可以重新措辞,以帮助后代:)),但我的解决方案看起来像这样:

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

相关内容

  • 没有找到相关文章

最新更新