Django - Слишком много одинаковых запросов
Я создаю приложение для рейтинга музыки и делаю сериализатор для альбомов, который имеет много отношений и один сериализатор метода агрегации, который, как я думаю, вызывает все проблемы. Метод получает среднее значение и количество рецензий для каждого альбома. Есть ли способ уменьшить количество запросов для повышения производительности?
Все мои модели
Вот как выглядит сериализатор альбомов.
"id": 2,
"title": "OK Computer",
"slug": "ok-computer",
"created_at": "2022-02-22T21:51:52.528148Z",
"artist": {
"id": 13,
"name": "Radiohead",
"slug": "radiohead",
"image": "http://127.0.0.1:8000/media/artist/images/radiohead.jpg",
"background_image": "http://127.0.0.1:8000/media/artist/bg_images/radiohead.jpg",
"created_at": "2022-02-22T00:00:00Z"
},
"art_cover": "http://127.0.0.1:8000/media/album/art_covers/ok-computer_cd5Vv6U.jpg",
"genres": [
"Alternative Rock",
"Art Rock"
],
"reviews": {
"overall_score": null,
"number_of_ratings": 0
},
"release_date": "1997-05-28",
"release_type": "LP",
"tracks": [
{
"position": 1,
"title": "Airbag",
"duration": "00:04:47"
},
{
"position": 2,
"title": "Paranoid Android",
"duration": "00:06:27"
}
],
"links": [
{
"service_name": "spotify",
"url": "https://open.spotify.com/album/6dVIqQ8qmQ5GBnJ9shOYGE?si=L_VNH3HeSMmGBqfiqKiGWA"
}
],
"aoty": null
Сериализатор альбомов с методом, который получает среднее значение и количество рецензий на альбом
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True, read_only=True)
genres = StringRelatedField(
source="album_genres", many=True, read_only=True)
aoty = StringRelatedField(read_only=True)
links = AlbumLinkSerializer(
source="album_links", many=True, read_only=True)
artist = SimpleArtistSerializer(source="artist_id")
def get_avg_and_count_of_reviews(self, album: Album):
reviews = Review.objects.only("rating").filter(album_id=album.id).aggregate(
overall_score=Avg(F("rating"), output_field=IntegerField()), number_of_ratings=Count(F("rating"), output_field=IntegerField()))
return reviews
reviews = serializers.SerializerMethodField(
method_name="get_avg_and_count_of_reviews")
class Meta:
model = Album
fields = ["id",
"title",
"slug",
"created_at",
"artist",
"art_cover",
"genres",
"reviews",
"release_date",
"release_type",
"tracks",
"links",
"aoty"]
# Save slug
def create(self, validated_data):
slug = slugify(validated_data["title"])
return Album.objects.create(slug=slug, **validated_data)
Здесь находится кверисет в альбоме Viewset
class AlbumViewSet(ModelViewSet):
queryset = Album.objects.prefetch_related("tracks").prefetch_related("album_genres").prefetch_related(
"album_links").prefetch_related("reviews").select_related("aoty").select_related("artist_id").all()
Сначала вам нужно изменить ваш агрегат, который вы вызываете один раз для каждого альбома, на аннотацию, это устранит все эти дополнительные запросы агрегации
class AlbumViewSet(ModelViewSet):
queryset = Album.objects.prefetch_related(
"tracks",
"album_genres",
"album_links",
"reviews"
).select_related(
"aoty",
"artist_id"
).annotate(
overall_score=Avg(F("reviews__rating"), output_field=IntegerField()),
number_of_ratings=Count(F("reviews__rating"), output_field=IntegerField())
)
Теперь вы можете заменить ваше поле reviews двумя обычными IntegerFields
class AlbumSerializer(serializers.ModelSerializer):
...
overall_score = serializers.IntegerField(source="overall_score")
number_of_ratings = serializers.IntegerField(source="number_of_ratings")
