首页 文章

Django REST框架:“此字段是必需的 . ”with required = False和unique_together

提问于
浏览
6

我想用Django REST Framework保存一个简单的模型 . 唯一的要求是在 perform_create() 方法中自动设置 UserVote.created_by . 这个例外失败了:

{
    "created_by": [
        "This field is required."
    ]
}

我想这是因为unique_together索引 .

models.py:

class UserVote(models.Model):
    created_by = models.ForeignKey(User, related_name='uservotes')
    rating = models.ForeignKey(Rating)

    class Meta:
        unique_together = ('created_by', 'rating')

serializers.py

class UserVoteSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(read_only=True)
    created_by = UserSerializer(read_only=True)

    class Meta:
        model = UserVote
        fields = ('id', 'rating', 'created_by')

views.py

class UserVoteViewSet(viewsets.ModelViewSet):
    queryset = UserVote.objects.all()
    serializer_class = UserVoteSerializer
    permission_classes = (IsCreatedByOrReadOnly, )

    def perform_create(self, serializer):
        serializer.save(created_by=self.request.user)

如何在不让用户提供 created_by 的情况下将模型保存在DRF中,而是在代码中自动设置此字段?

提前致谢!

3 回答

  • 0

    我有类似的问题,我通过显式创建并将新实例传递给序列化程序来解决它 . 在 UserVoteViewSet 中,您必须用 create 替换 perform_create

    def create(self, request, *args, **kwargs):
        uv = UserVote(created_by=self.request.user)
        serializer = self.serializer_class(uv, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
  • 7

    您可以做的另一种奇怪的方法是使用这样的信号

    @receiver(pre_save, sender=UserVote)
    def intercept_UserVote(sender, instance, *args, **kwargs):
        import inspect
        for frame_record in inspect.stack():
            if frame_record[3]=='get_response':
                request = frame_record[0].f_locals['request']
                break
        else:
            request = None
    
        instance.pre_save(request)
    

    那么基本上你可以在你的模型中定义pre_save

    def pre_save(self, request):
        # do some other stuff
        # Although it shouldn't happen but handle the case if request is None
        self.created_by = request.user
    

    该系统的优点是您可以为每个模型使用相同的代码 . 如果您需要更改任何内容,只需更改 pre_save() 即可 . 您也可以添加更多内容

  • 2

    我能用 views.py 中的单线来解决这个问题

    def create(self, request, *args, **kwargs):
        request.data.update({'created_by': request.user.id})
        return super(UserVoteViewSet, self).create(request, *args, **kwargs)
    

    由于此视图需要对用户进行身份验证,因此不要忘记为 rest_framework.permissions.IsAuthenticated 扩展 permission_classes

相关问题