使用 Meta 和查询参数中的默认字段创建 Django Serializer

Create Django Serializer with default fields in Meta and query params

我正在尝试编写一个序列化程序,它将采用动态字段并将它们添加到 Meta 中指定的限制数量的字段中,但似乎没有方法可以将字段“添加回”创建后的序列化程序。

每个 Django documentation

的动态字段
class DynamicFieldsModelSerializer(ModelSerializer):
    """
    A ModelSerializer that takes an additional `fields` argument that
    controls which fields should be displayed.
    """

    def __init__(self, *args, **kwargs):
        # Don't pass the 'fields' arg up to the superclass
        fields = kwargs.pop('fields', None)

        # Instantiate the superclass normally
        super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)

        if fields is not None:
            # Drop any fields that are not specified in the `fields` argument.
            allowed = set(fields)
            existing = set(self.fields)
            for field_name in existing - allowed:
                self.fields.pop(field_name)

class BldgLocationAndFilters(DynamicFieldsModelSerializer):
    latitude = fields.FloatField(source='lat_016_decimal')
    longitude = fields.FloatField(source='long_017_decimal')

    class Meta:
        model = Bldg
        fields = ('latitude', 'longitude')

我想做一些修改 DynamicFieldsModelSerializer 的事情,以便可以将字段附加到已经过滤掉的集合中,但看起来 Meta 字段覆盖了所有内容,因此无法添加任何内容(只能删除字段

所需行为的伪代码:

class DynamicFieldsUnionModelSerializer(ModelSerializer):
    """
    A ModelSerializer that takes an additional `fields` argument that
    controls which fields should be displayed.
    """

    def __init__(self, *args, **kwargs):
        # Don't pass the 'fields' arg up to the superclass
        fields = kwargs.pop('fields', None)

        # Instantiate the superclass normally
        super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)

        if fields is not None:
            new_fields = set(fields)
            existing = set(self.fields)
            unique_new = new_fields.union(existing) - existing
            for field_name in unique_new:
                self.fields.update(field_name)

如果 BldgLocationAndFilters 被调用为 serializer = BldLocationAndFilters(fields=['type']),我希望结果 returns 具有 fields = ('latitude', 'longitude', 'type')

DynamicFieldsModelSerializer 仅适用于删除现有字段,因为实现取决于已在 __init__ 中构建的字段。您可以在 __init__ 之后添加字段,但您必须以某种方式重新构建它们(不仅仅是添加名称)。

但支持这一点的一种方法是覆盖序列化程序的 get_field_names 方法,该方法与未构建的字段名称一起使用:

class BldgLocationAndFilters(ModelSerializer):
    latitude = fields.FloatField(source='lat_016_decimal')
    longitude = fields.FloatField(source='long_017_decimal')

    class Meta:
        model = Bldg
        fields = ('latitude', 'longitude')

    def __init__(self, *args, **kwargs):
        # Don't pass the 'fields' arg up to the superclass
        self._fields_to_add = kwargs.pop('fields', None)
        super().__init__(*args, **kwargs)

    def get_field_names(self, *args, **kwargs):
        original_fields = super().get_field_names(*args, **kwargs)
        if self._fields_to_add:
            return set(list(original_fields) + list(self._fields_to_add))
        return original_fields


# Should use latitude, longitude, and type
BldgLocationAndFilters(instance, fields=('type',)).data

请注意,这仅使用 ModelSerializer

或者只用 __all__ 定义序列化程序(同时仍然使用 DynamicFieldsModelSerializer)并根据需要设置字段:

class BldgLocationAndFilters(DynamicFieldsModelSerializer):
    latitude = fields.FloatField(source='lat_016_decimal')
    longitude = fields.FloatField(source='long_017_decimal')

    class Meta:
        model = Bldg
        fields = '__all__'


BldgLocationAndFilters(instance, fields=('latitude', 'longitude', 'type')).data