【问题标题】:How can I iterate through an SQL database using a function within a Django model?如何使用 Django 模型中的函数遍历 SQL 数据库?
【发布时间】:2019-11-17 20:36:23
【问题描述】:

我需要知道如何在 Django 模型中创建一个函数,该模型遍历 SQL 数据库,特别是另一个模型。

我的 Django 项目包含两个模型,“Accelerator”和“Review”。 Accelerator 模型有一个十进制字段“overall_rating”,其值取决于输入到 Review 模型字段之一“overall”中的值的累积。为了完成这项工作,我得出的结论是,我需要在 Accelerator 模型中创建一个函数:

  • 遍历 Review 模型数据库
  • 将 Review.overall 的值添加到满足特定条件的列表中
  • 计算列表的总值并将其除以列表长度以确定overall_rating 的值

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)

【问题讨论】:

  • 你不应该迭代你的数据库,而是聚合/注释。

标签: python sql django model


【解决方案1】:

您通常自己计算聚合,而是让数据库来做。数据库经过优化可以做到这一点。遍历集合会导致数据库需要传达所有相关记录,这将导致使用大量带宽。

如果您的目标是计算平均评分,您可以将review_setAvg aggregate [Django-doc] 相加,例如:

from django.db.models import Avg

class Accelerator(models.Model):

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

如果您需要对大量Accelerators 执行此操作,上述内容不是很有用,因为这会导致查询per Accelerator。但是,您可以 annotate(..) [Django-doc] 您的 Accelerator 类,例如使用 Manager [Django-doc]

from django.db.models import Avg

class AcceleratorManager(models.Manager):

    def get_queryset(self):
        return super().get_queryset().annotate(
            _average_rating=Avg('review__overall')
        )

然后我们可以修改Accelerator类,先看看这个值是否已经被注解计算出来了:

class Accelerator(models.Model):

    objects = models.Manager()
    objects_with_rating = AcceleratorManager()

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

如果我们随后访问例如Accelerator.objects_with_rating.filter(pk__lt=15),我们将批量计算这些Accelerators 的平均评分。

将平均值存储在数据库中可能不是一个好主意,因为它引入了数据重复,而同步数据重复往往是一个难题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-22
    • 2017-08-13
    • 1970-01-01
    • 2014-07-19
    • 2021-04-20
    • 2016-01-09
    • 1970-01-01
    相关资源
    最近更新 更多