Django Rest Framework - 注释重复值

Django Rest Framework - Annotate duplicates values

我遇到了一个非常奇怪的错误。在注释 3 个值(AVG、COUNT 和 SUM)时,我注意到 COUNT 和 SUM 相互相乘。

例如:

持续时间应该是一半,并且只有 2 个评分(number_of_ratings - COUNT,album_duration - SUM)。

我在 ViewSet 的查询集中有这些注释 class

class AlbumViewSet(ModelViewSet):
    queryset = Album.objects \
        .prefetch_related("tracks", "album_genres", "album_genres__genre_id", "album_links", "reviews") \
        .select_related("aoty", "artist_id") \
        .annotate(overall_score=Avg("reviews__rating", output_field=IntegerField()),
                  number_of_ratings=Count("reviews__rating", output_field=IntegerField()),
                  album_duration=Sum("tracks__duration", output_field=DurationField()))

这是其他文件

models.py

class Album(models.Model):

    RELEASE_TYPE_ALBUM_CHOICES = [
        ("LP", "LP"),
        ("EP", "EP"),
        ("Single", "Single"),
        ("Live", "Live"),
    ]

    title = models.CharField(max_length=255)
    slug = models.SlugField(max_length=255)
    release_date = models.DateField()
    artist_id = models.ForeignKey(
        Artist, on_delete=models.PROTECT, related_name="albums"
    )
    art_cover = ResizedImageField(
        size=[750, 750], null=True, blank=True, upload_to=rename_album_art_cover)
    release_type = models.CharField(max_length=10,
                                    choices=RELEASE_TYPE_ALBUM_CHOICES, default="LP")
    created_at = models.DateTimeField(auto_now_add=True)


class Track(models.Model):
    title = models.CharField(max_length=255)
    position = models.PositiveIntegerField()
    album_id = models.ForeignKey(
        Album, on_delete=models.PROTECT, related_name="tracks")
    duration = models.DurationField(null=True)


class Review(models.Model):
    reviewer_id = models.ForeignKey(Reviewer, on_delete=models.PROTECT)
    rating = models.IntegerField(
        validators=[MaxValueValidator(100), MinValueValidator(0)]
    )
    review_text = models.TextField(null=True, blank=True)
    album_id = models.ForeignKey(
        Album, on_delete=models.PROTECT, related_name="reviews")
    created_at = models.DateTimeField(auto_now_add=True)

serializer.py

class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackSerializer(many=True)
    genres = StringRelatedField(
        source="album_genres", many=True)
    aoty = StringRelatedField(read_only=True)
    links = AlbumLinkSerializer(
        source="album_links", many=True, read_only=True)
    artist = SimpleArtistSerializer(source="artist_id", read_only=True)
    overall_score = serializers.IntegerField(read_only=True)
    number_of_ratings = serializers.IntegerField(read_only=True)
    album_duration = serializers.DurationField(read_only=True)

    class Meta:
        model = Album
        fields = [
            "id",
            "title",
            "slug",
            "created_at",
            "artist",
            "art_cover",
            "genres",
            "overall_score",
            "number_of_ratings",
            "release_date",
            "release_type",
            "tracks",
            "album_duration",
            "links",
            "aoty"
        ]

class TrackSerializer(serializers.ModelSerializer):
    class Meta:
        model = Track
        fields = ["position", "title",  "duration", "album_id"]

class ReviewSerializer(serializers.ModelSerializer):
    reviewer = SimpleReviewerSerializer(source="reviewer_id", read_only=True)
    album = ReviewAlbumSerializer(source="album_id", read_only=True)

    class Meta:
        model = Review
        fields = [
            "id",
            "reviewer_id",
            "reviewer",
            "rating",
            "review_text",
            "album_id",
            "album",
            "created_at"
        ]

对于遇到相同问题的任何人,以下是我的解决方法。 每个注释函数中都应该设置不同的属性。

.annotate(overall_score=Avg("reviews__rating", output_field=IntegerField()),
                  number_of_ratings=Count("reviews__rating", output_field=IntegerField(), distinct=True),
                  album_duration=Sum("tracks__duration", output_field=DurationField(), distinct=True))