Перехват и замена полей сериализатора при инициализации в Django
Итак, у меня есть Django проект с Django REST Framework с большим количеством моделей. Чтобы фронтенд был удобным для пользователя, я должен отображать не только id связанного объекта, но и его имя. Моя идея решения заключалась в замене всех полей PrimaryKeyRelated на StringRelatedFields в сериализаторах ответа. Поскольку количество моделей велико, я решил сделать один абстрактный сериализатор/миксин и перехватывать создание полей, заменяя их, если они имеют правильный тип. Вот до чего я дошел на данный момент:
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