Django模型从外键模型获取重复数据

0 投票
3 回答
1045 浏览
提问于 2025-05-10 15:17

我有两个模型,一个是用来创建标题的,另一个是用来给这个标题投票的。

当我对同一个标题创建多个投票时,出现了重复的标题,我搞不清楚为什么会这样。

这是我的投票模型:

class Vote(GenericModel):
    """
    Model for vote on a title
    """
    title = models.ForeignKey(Title, blank=True, related_name='votes')

    user = models.ForeignKey(ArtLover, blank=True)

    def __str__(self):
        return _("vote on {}").format(self.title.__str__())

这是投票的视图:

@detail_route(methods=['post'])
def vote(self, request, *args, **kwargs):
    """
    Create vote for a title
    """
    title = Title.objects.get(text=kwargs.get('text'))
    user = ArtLover.objects.get(id=request.user.id)

    if title.user.id == user.id:
        return Response(
            _("You can't vote for your own title"),
            status=status.HTTP_403_FORBIDDEN
        )

    if Vote.objects.filter(title=title, user=user).exists():
        return Response(
            _("Vote already exists"),
            status=status.HTTP_409_CONFLICT
        )

    vote = Vote.objects.create(title=title, user=user)

    return Response({
        'vote': VoteSerializer(vote).data
    }, status=status.HTTP_201_CREATED)

如果我在创建投票后打印标题的实例数量,数量是正确的,没有重复,所以我猜测重复是在后面发生的。你能告诉我重复是在哪里/为什么发生的吗?

当我删除投票时,由重复产生的标题也会被删除。

编辑 1:

我尝试为标题模型创建一个自定义管理器来阻止重复,但当在创建投票时发生重复时,标题管理器并没有被调用。

当我比较原始模型实例的主键和重复的主键时,它们是一样的。

编辑 2:

我在尝试对艺术作品序列化器中的标题字段进行排序。

我的艺术作品序列化器:

class ArtworkDetailSerializer(serializers.ModelSerializer):
    """
    Detailed serializer for Artwork
    """
    artist = serializers.CharField(source='artist.username', read_only=True)
    titles = TitleSerializer(many=True)
    emotions = serializers.SerializerMethodField()

    class Meta:
        model = Artwork
        fields = ('id', 'file', 'artist', 'index', 'url', 'titles', 'emotions')
        read_only_fields = ('id', 'artist', 'index', 'url', 'titles', 'emotions')

我的标题序列化器:

class TitleSerializer(serializers.ModelSerializer):
    """
    Serializer for title suggested by user
    """
    votes = VoteSerializer(many=True, read_only=True)
    user = serializers.CharField(source='user.username', read_only=True)
   artwork = serializers.CharField(source='artwork.url', read_only=True)

    class Meta:
        model = Title
        fields = ('id', 'artwork', 'text', 'user', 'votes',)
        read_only_fields = ('id', 'artwork', 'user', 'votes',)

我的艺术作品视图:

class ArtworkView(viewsets.ModelViewSet):
    """
    View that handle Artwork
    """
    lookup_field = 'url'
    queryset = Artwork.objects.all()
    permission_classes = (
        permissions.IsAuthenticatedOrReadOnly,
        IsArtistOrReadOnly,
    )

    def get_serializer_class(self):
        if self.action == 'retrieve':
            return ArtworkDetailSerializer
        return ArtworkSerializer

相关文章:

  • 暂无相关问题
暂无标签

3 个回答

0

问题出在我的标题模型上:

class Title(GenericModel):
    """
    Model for title suggested by user
    """
    class Meta:
        ordering = ['votes']

    text = models.CharField(_('text'), max_length=255)

    artwork = models.ForeignKey(Artwork, blank=True,    related_name='titles')

    user = models.ForeignKey(ArtLover, blank=True)

    def __str__(self):
        return self.text

在元数据中的排序每次我投票时都会重复这个模型,为什么会这样呢?我应该怎么根据投票数量来排序我的标题呢?

0

你可以试着把这段代码:

vote = Vote.objects.create(title=title, user=user)

换成:

vote, created = Vote.objects.get_or_create(title=title, user=user)

1

当你按照相关字段 votes 排序时,这会导致 Django 进行左外连接。如果一个标题关联了多个投票,它会在查询结果中根据每个投票返回一次。

注意,保存投票并不是在创建重复项。你可以通过按其他字段排序来确认这一点,并检查数量。正如你在问题中提到的,重复项的主键是相同的,所以你并没有在数据库中创建额外的标题,查询结果只是多次返回相同的标题。

Title.objects.order_by('pk').count()

要按照投票数量排序,你需要在查询集中添加投票数量的注释,然后根据这个注释进行排序:

Title.objects.annotate(num_votes=Count('votes')).order_by('num_votes')

撰写回答