【问题标题】:Modify Django Rest Framework ModelViewSet behavior修改 Django Rest Framework ModelViewSet 行为
【发布时间】:2014-08-24 20:46:11
【问题描述】:

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

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 到我的 API 的新 ShellMessage 时,我不想提供“创建者”的 foreignKey,而只是提供该人的用户名,然后在我的 ViewSet 中处理它以找到与此用户名关联的用户和将它保存在我的 ShellMessage 对象中。

如何使用 Django rest 框架实现这一点?我想增强 create() 或 pre_save() 方法,但我被卡住了,因为我的所有更改都会覆盖“正常”框架行为并导致意外错误。

谢谢。

【问题讨论】:

    标签: django django-rest-framework


    【解决方案1】:

    更新:此主题似乎与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 列出了viewsets.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”设置的任何值。

    【讨论】:

      【解决方案2】:

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

      所以我做了以下事情:

      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)
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-13
        • 1970-01-01
        • 2016-08-01
        • 2021-12-02
        • 1970-01-01
        • 2015-11-08
        相关资源
        最近更新 更多