Django DRF ModelViewSet中用于CREATE的可选pk参数

时间:2018-11-22 14:30:08

标签: django django-rest-framework

我有一个用于我的模型的常规ModelViewSet,但是我希望可以选择指定特定的PK来创建新实例。例如。如果我要发表:

{
    "name": "Name"
}

它将获得随机pk。但是如果我发布:

{
    "id": "123",
    "name": "Name"
}

我希望它具有指定的pk(id)。

类似于this人,我所做的就是像这样将id字段添加到我的ModelSerializer中:

class ConversationViewSet(viewsets.ModelViewSet):
    """
    List all conversations, or create new / edit existing product.
    """
    queryset = Conversation.objects.all()
    serializer_class = ConversationSerializer

class ConversationSerializer(serializers.ModelSerializer):
    id = serializers.CharField(required=False)  # Instead of serializer.ReadOnlyField()

    class Meta:
        model = Conversation
        fields = '__all__'

虽然此方法适用于create方法,但会引起updatepartial_update问题,其中id现在是查询字符串参数的必需参数,而在这样的请求正文中(来自文档):

update
PUT /conversations/{id}/
Update existing conversation.

Path Parameters
The following parameters should be included in the URL path.

Parameter       Description
id (required)   A unique value identifying this conversation.

Request Body
The request body should be a "application/json" encoded object, containing the following items.

Parameter       Description
id  
access_token    
username    
password    
app_user_id 
name    

具有两个相同名称的参数当然是不好的做法。例如。在使用requests并传递参数字典时,该键不再起作用,因为它不知道我要寻址哪个参数。

如何解决这个问题,使得id参数仅对create方法是可选的,但所有其他方法(列表,读取,...)与默认方法完全相同情况?

我的解决方案

根据JPG的答案,我将序列化器修改为:

class ConversationSerializer(serializers.ModelSerializer):
    id = serializers.ReadOnlyField()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.context['view'].action == 'create':
            self.fields['id'] = serializers.CharField(required=False)

    class Meta:
        model = Conversation
        fields = '__all__'

1 个答案:

答案 0 :(得分:2)

我认为可以通过重写序列化程序的 __init__() 方法来实现。

class ConversationSerializer(serializers.ModelSerializer):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.context['view'].action == 'create':
            self.fields['id'] = serializers.CharField()
        else:
            self.fields['id'] = serializer.ReadOnlyField()

    class Meta:
        model = Conversation
        fields = '__all__'