【问题标题】:Create Django Serializer with default fields in Meta and query params使用 Meta 中的默认字段和查询参数创建 Django 序列化程序
【发布时间】:2021-08-25 20:31:35
【问题描述】:

我正在尝试编写一个序列化程序,它将采用动态字段并将它们添加到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']),我希望得到的返回值为 fields = ('latitude', 'longitude', 'type')

【问题讨论】:

    标签: python django django-rest-framework django-serializer


    【解决方案1】:

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-29
      • 2021-12-28
      • 2015-10-19
      • 2015-02-09
      • 2015-09-02
      • 2019-04-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多