Django совокупное Среднее против для l oop с prefetch_related () - PullRequest
1 голос
/ 16 июня 2020

У меня есть модель обзора, которая находится во взаимосвязи один к одному с моделью оценки. Пользователь может выставить оценку по шести различным критериям - чистота, коммуникация, check_in, точность, местоположение и значение - которые определены как поля в модели оценки.

class Rating(models.Model):
    cleanliness     = models.PositiveIntegerField()
    communication   = models.PositiveIntegerField()
    check_in        = models.PositiveIntegerField()
    accuracy        = models.PositiveIntegerField()
    location        = models.PositiveIntegerField()
    value           = models.PositiveIntegerField()

class Review(models.Model):
    room       = models.ForeignKey('room.Room', on_delete=models.SET_NULL, null=True)
    host       = models.ForeignKey('user.User', on_delete=models.CASCADE, related_name='host_reviews')
    guest      = models.ForeignKey('user.User', on_delete=models.CASCADE, related_name='guest_reviews')
    rating     = models.OneToOneField('Rating', on_delete=models.SET_NULL, null=True)
    content    = models.CharField(max_length=2000)

Я думаю о способе расчета общей оценки, которая была бы средним значением для каждого столбца в модели рейтинга. Одним из способов может быть использование функции aggregate () Django, а другим вариантом может быть предварительная выборка всех обзоров и циклическое прохождение каждого обзора для ручного расчета общей оценки. Например,

for room in Room.objects.all()
    ratings_dict = Review.objects.filter(room=room)\
            .aggregate(*[Avg(field) for field in ['rating__cleanliness', 'rating__communication', \
               'rating__check_in', 'rating__accuracy', 'rating__location', 'rating__value']])
    ratings_sum = 0
    for key in ratings_dict.keys():
        ratings_sum += ratings_dict[key] if ratings_dict[key] else 0

Или, просто перебирая,

rooms = Room.objects.prefetch_related('review_set')
for room in rooms:
    reviews   = room.review_set.all()
    ratings   = 0
    for review in reviews:
        ratings += (review.rating.cleanliness + review.rating.communication + review.rating.check_in + 
                        review.rating.accuracy + review.rating.location+ review.rating.value)/6

Какой способ будет более эффективным с точки зрения временной сложности и приведет к меньшему количеству обращений к БД?

Создает ли агрегат (Avg ('field_name')) один запрос Avg на уровне базы данных для каждого вызова функции?

Будет ли сначала вызов всех комнат с помощью prefetch_related () помочь уменьшить количество запросов позже при вызове room.review_set. все ()?

...