修改Django Rest Framework ModelViewSet行为

时间:2014-07-03 16:06:27

标签: django django-rest-framework

我的项目中基本上有以下模型:

class ShellMessage(TimeStampedModel):
    # There is a hidden created and modified field in this model.
    ACTION_TYPE = (
        ('1' , 'Action 1'),
        ('2' , 'Action 2')
    )
    type    = models.CharField(max_length=2,choices=ACTION_TYPE,default='1')
    action  = models.CharField(max_length=100)
    result  = models.CharField(max_length=300, blank=True)
    creator = models.ForeignKey(User)

我创建了一个序列化程序:

class ShellMessageSerializer(serializers.ModelSerializer):
    class Meta:
        model = ShellMessage
        fields = ('action', 'type', 'result', 'creator')

还有一个ModelViewSet:

class ShellListViewSet(viewsets.ModelViewSet):
    serializer_class = ShellMessageSerializer
    queryset = ShellMessage.objects.all()

我的问题如下: 当我使用POST创建一个新的ShellMessage到我的API时,我不想提供'creator'的foreignKey,而只是提供该人的用户名,然后在我的ViewSet中处理它以找到与此用户名相关联的用户将它保存在我的ShellMessage对象中。

如何使用Django rest Framework实现这一目标?我想要增加create()或pre_save()方法,但是因为我的所有更改都覆盖了“正常”的框架行为并导致意外错误而陷入困境。

谢谢。

2 个答案:

答案 0 :(得分:1)

我在发布问题后终于找到了我的解决方案:)

所以我做了以下事情:

class ShellListViewSet(viewsets.ModelViewSet):
    serializer_class = ShellMessageSerializer
    queryset = ShellMessage.objects.all()

    def pre_save(self, obj):
        obj.creator = self.request.user
        return super(ShellListViewSet, self).pre_save(obj)

这是按预期工作的。我希望我做得很好。

答案 1 :(得分:0)

更新:本主题似乎与Editing django-rest-framework serializer object before save

相同

如果打算在对象保存到模型数据库中之前对其进行拦截和执行某些处理,那么您正在寻找的是覆盖方法“ perform_create”(用于POST)或“ perform_update”(用于PUT / PATCH)出现在viewsets.ModelViewSet类中。

此参考文献http://www.cdrf.co/3.1/rest_framework.viewsets/ModelViewSet.html列出了viewsset.ModelViewSet中所有可用的方法,您可以在其中看到“ create”方法调用“ perform_create”,这反过来通过序列化程序对象(可以访问的对象)执行实际的保存。模型):

def perform_create(self, serializer):
    serializer.save()

我们可以通过派生类(在此示例中为ShellListViewSet)覆盖基类(viewsets.ModelViewSet)中存在的此功能,并修改要在保存时更改的模型属性:

class ShellListViewSet(viewsets.ModelViewSet):
    serializer_class = ShellMessageSerializer
    queryset = ShellMessage.objects.all()

    def findCreator(self):
        # You can perform additional processing here to find proper creator
        return self.request.user

    def perform_create(self, serializer):
        # Save with the new value for the target model fields
        serializer.save(creator = self.findCreator())

您还可以选择分别修改模型字段,然后保存(可能不建议使用,但可以):

serializer.validated_data['creator'] = self.findCreator()
serializer.save()

稍后,如果对象已经创建,并且您还想在更新期间应用相同的逻辑(PUT,PATCH),则可以在“ perform_update”中通过“ serializer.validated_data ['creator”执行与上述相同的操作']”,也可以直接通过实例进行更改:

serializer.instance.creator = self.findCreator()
serializer.save()

但是要提防直接从https://www.django-rest-framework.org/api-guide/serializers/开始通过实例进行这种更新:

class MyModelSerializer(serializers.Serializer):
    field_name = serializers.CharField(max_length=200)

    def create(self, validated_data):
        return MyModel(**validated_data)

    def update(self, instance, validated_data):
        instance.field_name = validated_data.get('field_name', instance.field_name)
        return instance

这意味着,如果在“ validated_data”中设置了“ field_name”数据集,则分配给“ instance.field_name”对象的任何内容都将被覆盖(换句话说,如果PUT / PATCH请求的HTTP正文包含特定的“ field_name”,从而导致它出现在“ validated_data”中,因此将覆盖您为“ instance.field_name”设置的任何值。)