首页 > 解决方案 > 如何使用 Django 模型中的函数遍历 SQL 数据库?

问题描述

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

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

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)

标签: pythonsqldjangomodel

解决方案


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

如果您的目标是计算平均评分,您可以review_set使用Avg聚合 [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']

如果您需要对大量 s 执行此操作,则上述内容不是很有用Accelerator,因为这会导致每个 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 的平均评分。

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


推荐阅读