在Django中初始化时截取并替换序列化程序字段

2024-04-28 22:18:44 发布

您现在位置:Python中文网/ 问答频道 /正文

因此,我有一个Django项目,其中有Django REST框架和大量模型。为了使前端对用户友好,我不仅要显示相关对象的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函数,但我猜当所有字段实例都已创建时,该函数在流中出现得太晚了。我应该重写哪个函数


2条回答
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

相关问题 更多 >