Skip to main content
 首页 » 编程设计

python之具有动态选项的 Django Rest Framework MultipleChoiceField

2025年01月19日38lonelyxmas

所以我刚开始使用 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') 

但是,当我添加一个新的参数对象时,选择并没有更新。在常规的 Django 表单中,我简单地使用

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

它会在添加新参数时更新选择,而无需重新启动服务器。我如何使用 Django Rest Framework 序列化器完成同样的事情?

感谢任何帮助。谢谢!

请您参考如下方法:

当您选择模型时,最直接的方法是使用 RelatedField 的一些派生词.鉴于您正在使用 p.id , 做 PrimaryKeyRelatedField为你工作? (如果没有,请更新您的问题)

如果默认行为(使用模型的 __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> ,我相信这就是您需要做的。


ChoiceField和 MultipleChoiceField旨在处理静态数据集。他们甚至在 __init__ 预处理东西允许分组。这就是为什么新项目不会出现在那里的原因 - 这些字段本质上永远“缓存”结果(直到服务器重新启动)。

如果出于某种原因,你真的需要它是 ChoiceField -导数,可以设置post_save和 post_delete信号监听器和更新字段' choices (和 grouped_choices,如果您使用的不是已经包含 PR to allow choices to be set dynamically 的非常前沿的版本)属性。检查 ChoiceField source code了解详情。不过,那将是一个肮脏的黑客。 ;)