Как динамически установить поля сериализатора (не во время инициализации)? - PullRequest
0 голосов
/ 11 января 2019

Я пытаюсь исключить поля вложенного-сериализатора. Как мне это сделать?

Например, для сериализатора

class UserDetailSerializer(serializers.ModelSerializer):
   user  = UserSerializer() # want to exclude fields in this serializer
   other = OtherSerializer()

   class Meta:
       model = User

Это должно работать как

serialized = UserDetailSerializer(user_detail, exclude=['fields'])

И значения исключения должны быть переданы в другие сериализаторы, то есть как в UserSerializer, так и в OtherSerializer.

У меня есть измененная версия DynamicFieldsModelSerializer в документации по drf, но она работает только для класса, который наследует ее.

class DynamicFieldsModelSerializer(serializers.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)
        exclude = kwargs.pop('exclude', None)

        # Instantiate the superclass normally
        super().__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.keys())
            for field_name in existing - allowed:
                self.fields.pop(field_name)
        elif exclude is not None:  
            # drop fields that are specified in the 'exclude' argument
            for field_name in set(exclude):
                self.fields.pop(field_name)

1 Ответ

0 голосов
/ 14 января 2019

Хорошо, я нашел решение здесь: https://stackoverflow.com/a/37186932/10531996

А вот отредактированная версия с поддержкой полей с несколькими значениями:

class NestedDynamicFieldsModelSerializer(serializers.ModelSerializer):

def __init__(self, *args, **kwargs):

    def parse_nested_fields(fields):
        field_object = {"fields": []}
        for f in fields:
            obj = field_object
            nested_fields = f.split("__")
            for v in nested_fields:
                if v not in obj["fields"]:
                    obj["fields"].append(v)
                if nested_fields.index(v) < len(nested_fields) - 1:
                    obj[v] = obj.get(v, {"fields": []})
                    obj = obj[v]
        return field_object

    def select_nested_fields(serializer, fields):
        for k in fields:
            if k == "fields":
                fields_to_include(serializer, fields[k])
            else:
                select_nested_fields(serializer.fields[k], fields[k])

    def fields_to_include(serializer, fields):
        # Drop any fields that are not specified in the `fields` argument.
        allowed = set(fields)
        if isinstance(serializer, serializers.ListSerializer):
            existing = set(serializer.child.fields.keys())
            for field_name in existing - allowed:
                serializer.child.fields.pop(field_name)
        else:
            existing = set(serializer.fields.keys())
            for field_name in existing - allowed:
                serializer.fields.pop(field_name)

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

    if fields is not None:
        # import pdb; pdb.set_trace()
        fields = parse_nested_fields(fields)
        # Drop any fields that are not specified in the `fields` argument.
        select_nested_fields(self, fields)

Использование:

serialized = ClassSerializer(instance, fields=[
    field, 
    field2__value1, field2__value2, 
    field3__field1__value1
])
...