unique_together不允许更新记录

时间:2015-07-27 06:41:40

标签: python django api django-rest-framework

我正致力于通过Django Rest Framework在移动应用API的API中实现Like / Different功能。

所以我有以下型号:

class PlaylistLikes(models.Model):
    user = models.ForeignKey(User)
    playlist = models.ForeignKey(Playlist)
    like = models.BooleanField(default=0, blank=True)

    class Meta:
        unique_together = ('user', 'playlist',)
        verbose_name = "Playlist like"
        verbose_name_plural = "Playlist likes"

我添加了unique_together来限制用户喜欢他已经喜欢的播放列表。

我的观点:

class LikesView(viewsets.ModelViewSet):
    queryset = PlaylistLikes.objects.all()
    serializer_class = LikesSerializer
    filter_backends = (filters.OrderingFilter, filters.DjangoFilterBackend, filters.SearchFilter)
    filter_class = LikesFilter

    search_fields = ('playlist', 'user',)

    def create(self, request, *args, **kwargs):
        user = request.user
        request.data['user'] = user.pk
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    @detail_route(methods=['put'])
    def put(self, request, *args, **kwargs):
        user = request.user
        request.data['user'] = user.pk
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)
        return Response(serializer.data, status=status.HTTP_200_OK)

序列化器:

class LikesSerializer(serializers.ModelSerializer):

    def create(self, validated_data):
        like = PlaylistLikes.objects.create(**validated_data)
        playlist = Playlist.objects.get(pk=like.playlist.id)
        playlist.likes_count += 1
        playlist.save()
        return validated_data

    def update(self, instance, validated_data):
        like = PlaylistLikes.objects.get(**validated_data)
        like.like = False
        like.save()
        playlist = Playlist.objects.get(pk=like.playlist.id)
        playlist.likes_count -= 1
        playlist.save()
        return validated_data

    class Meta:
        model = PlaylistLikes
        fields = ('user', 'playlist', 'like')

的url:

router.register(r'likes', views.LikesView, 'likes')

为了喜欢播放列表,我发送POST方法与正文playlist = 19user = 3like = 1。喜欢成功创造。 与不同的播放列表不同,我发送PUT方法与正文:playlist = 19user = 3,但我收到了以下错误:

  

“non_field_errors”:[       “字段用户,播放列表必须创建一个唯一的集合。” ]

我理解它是因为模型中的unique_together而发生的。但我没有创建具有相同userplaylist的新记录。我只想更新现有记录。为什么会发生这种情况以及如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

这是因为在PUT方法处理程序中,您创建了一个序列化程序而没有指定实例:

serializer = self.get_serializer(data=request.data)

查看Serializer.__init__()

def __init__(self, instance=None, data=empty, **kwargs):
    self.instance = instance
    if data is not empty:
        self.initial_data = data
    self.partial = kwargs.pop('partial', False)
    self._context = kwargs.pop('context', {})
    kwargs.pop('many', None)
    super(BaseSerializer, self).__init__(**kwargs)

您没有提供实例参数,默认为None。

对于更新,仅当实例属性不是None:

时,才应跳过unique_together验证
class UniqueTogetherValidator(object):
    def exclude_current_instance(self, attrs, queryset):
        """
        If an instance is being updated, then do not include
        that instance itself as a uniqueness conflict.
        """
        if self.instance is not None:
            return queryset.exclude(pk=self.instance.pk)
        return queryset

要解决此问题,您可以在初始化序列化程序之前移动Userlikes对象的查询:

like = PlaylistLikes.objects.get(**query)
serializer = self.get_serializer(like, data=request.data)