Django Rest Framework具有动态选项的MultipleChoiceField

时间:2017-10-12 17:57:04

标签: python django django-rest-framework

所以我刚开始使用Django Rest Framework,我的一个序列化程序有一个MultipleChoiceField,其中的选项只是另一个模型的所有实例。

以下是有问题的序列化程序:

class ObjectTypeSerializer(serializers.ModelSerializer):

    def get_field_choices():
        return sorted([
            (p.id, p.name) for p in Parameter.objects.all()
        ])

    object_fields = serializers.MultipleChoiceField(
        choices=get_field_choices()
    )

    instance_fields = serializers.MultipleChoiceField(
        choices=get_field_choices()
    )

    labels = serializers.SlugRelatedField(
        queryset=Label.objects.all(),
        many=True, allow_null=True, slug_field='name'
    )

    class Meta:
        model = ObjectType
        fields = ('id', 'name', 'object_fields',
                    'instance_fields', 'labels')

但是,当我添加新的Parameter对象时,选项不会更新。在常规的Django表单中,我使用

解决了这个问题
forms.ChoiceField(choices=[(p.id, p.name) for p in Parameter.objects.all()]) 

并且在没有重新启动服务器的情况下添加新参数时会更新选项。如何使用Django Rest Framework序列化器完成同样的事情?

感谢任何帮助。谢谢!

1 个答案:

答案 0 :(得分:1)

当您选择模型时,最直接的方法是使用RelatedField的一些衍生物。鉴于您使用p.idPrimaryKeyRelatedField是否适合您? (如果没有,请更新您的问题)

如果默认行为(使用模型的__unicode__作为显示值)不是您想要的,您可以始终对其进行子类化并重新定义display_value方法:

class CustomPKRelatedField(serializers.PrimaryKeyRelatedField):
    """A PrimaryKeyRelatedField derivative that uses named field for the display value."""

    def __init__(self, **kwargs):
        self.display_field = kwargs.pop("display_field", "name")
        super(CustomPKRelatedField, self).__init__(**kwargs)

    def display_value(self, instance):
        # Use a specific field rather than model stringification
        return getattr(instance, self.display_field)

...
class ObjectTypeSerializer(serializers.ModelSerializer):
    ...
    object_fields = CustomPKRelatedField(queryset=Parameter.objects.all(), many=True)
    instance_fields = CustomPKRelatedField(queryset=Parameter.objects.all(), many=True)
    ...
...

如果你需要的只是BrowsableAPIRenderer会呈现一个漂亮的<select>,我相信这就是你需要做的一切。

ChoiceFieldMultipleChoiceField旨在处理静态数据集。他们甚至在__init__预处理事物以允许分组。这就是为什么新项目不会出现在那里 - 这些字段实质上是“缓存”结果(直到服务器重新启动)。

如果由于某种原因,您确实需要它ChoiceField - 衍生物,您可以设置post_savepost_delete个单一听众并更新字段'choices(和grouped_choices如果你没有处于已经包含PR to allow choices to be set dynamically的非常前沿版本的属性。查看ChoiceField source code了解详情。不过,这将是一个肮脏的黑客。 ;)