Как я могу перебрать базу данных SQL, используя функцию в модели Django? - PullRequest
1 голос
/ 08 июля 2019

Мне нужно знать, как я могу создать функцию в модели Django, которая перебирает базу данных SQL, в частности другую модель.

Мой проект Django содержит две модели: «Ускоритель» и «Обзор». Модель Accelerator имеет десятичное поле 'total_rating', значение которого должно зависеть от накопления значений, введенных в одно из полей модели обзора, 'total'. Чтобы сделать эту работу, я пришел к выводу, что мне нужно создать функцию в модели ускорителя, которая:

  • Итерация по базе данных модели обзора
  • Добавляет значение Review.overall в список, где выполняется определенное условие
  • Вычисляет общее значение списка и делит его на длину списка, чтобы определить значение для общего рейтинга

Значение accelerator.overall_rating будет подвержено изменению (т. Е. Его необходимо будет обновлять всякий раз, когда будет опубликован новый обзор этого «ускорителя», и, следовательно, будет добавлено новое значение для review.overall). Итак, мои вопросы:

  • Будет ли вставка функции в мою модель ускорителя, чтобы ее значение изменилось в соответствии с входными данными модели обзора?
  • Если да, какой синтаксис необходим для итерации содержимого модели обзора моей базы данных?

(я включил только соответствующие поля модели в общий код)

class Accelerator(models.Model):
    overall_rating = models.DecimalField(decimal_places=2, max_digits=3)

class Review(models.Model):
    subject = models.ForeignKey(Accelerator, on_delete=models.CASCADE, blank=False)
    overall = models.DecimalField(decimal_places=2, max_digits=3)

1 Ответ

1 голос
/ 08 июля 2019

Вы обычно не сами рассчитываете агрегаты, но дайте базе данных сделать это. Базы данных оптимизированы для этого. Итерирование по коллекции приведет к тому, что базе данных потребуется передать все соответствующие записи, что приведет к использованию большой полосы пропускания.

Если вы хотите рассчитать средний рейтинг, вы можете просто агрегировать по review_set с Avg агрегат [Django-doc] , например:

from django.db.models import <b>Avg</b>

class Accelerator(models.Model):

    @property
    def average_rating(self):
        return self.<b>review_set</b>.aggregate(
            <b>average_rating=Avg('overall')</b>
        )['average_rating']

Вышеприведенное не очень полезно, если вам нужно сделать это для большого набора Accelerator с, поскольку это приведет к запросу за Accelerator. Однако вы можете annotate(..) [Django-doc] ваш Accelerator класс, например, с Manager [Django-doc]

from django.db.models import Avg

class AcceleratorManager(models.Manager):

    def <b>get_queryset</b>(self):
        return super().get_queryset().<b>annotate</b>(
            _average_rating=Avg('review__overall')
        )

Затем мы можем изменить класс Accelerator, чтобы сначала посмотреть, вычислено ли значение аннотацией:

class Accelerator(models.Model):

    objects = models.Manager()
    <b>objects_with_rating = AcceleratorManager()</b>

    @property
    def average_rating(self):
        try:
            return self._average_rating
        except AttributeError:
            self._average_rating = result = self.<b>review_set</b>.aggregate(
                average_rating=Avg('overal')
            )['average_rating']
            return result

Если затем мы получим, к примеру, Accelerator.objects_with_rating.filter(pk__lt=15), мы массово вычислим средний рейтинг этих Accelerator с.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...