首页 > 解决方案 > Django ORM 中的动态视图 - 最佳方法?

问题描述

一些背景

我正在考虑使用 Django 重建现有的 Laravel 网站。这是一个允许共享来自无人机/无人机推进组件的基准数据的网站。一些基准测试是在同时测试多个电机和螺旋桨时完成的,这意味着一个电池将承受多个电机的负载,但这也意味着来自一个螺旋桨的气流会影响另一个螺旋桨上捕获的数据。这意味着数据是物理耦合的。这是一个例子。现在我正在尝试构建这个项目以允许即将推出的功能,并查看 Django ORM 是否适合。

简化的 Django 模型

class Benchmark(models.Model):
    title = models.CharField()
    private = models.BooleanField(default=False)
    hide_torque = models.BooleanField(default=False)


class AbstractComponent(models.Model):
    brand = models.CharField()
    name = models.CharField()

    class Meta:
        abstract = True


class Motor(AbstractComponent):
    shaft_diameter_mm = models.FloatField()


class Propeller(AbstractComponent):
    diameter_in = models.FloatField()


class Battery(AbstractComponent):
    capacity_kwh = models.FloatField()


class Powertrain(models.Model):
    benchmark = models.ForeignKey(Benchmark, on_delete=models.CASCADE, related_name='powertrains')
    motor = models.ForeignKey(Motor, on_delete=models.CASCADE)
    propeller = models.ForeignKey(Propeller, on_delete=models.CASCADE, blank=True, null=True)
    battery = models.ForeignKey(Battery, on_delete=models.CASCADE, blank=True, null=True)


class DerivedDataManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset()\
            .annotate(electrical_power_w=F('voltage_v') * F('current_a'))\
            .annotate(mechanical_power_w=F('torque_nm') * F('rotation_speed_rad_per_s'))\
            .annotate(motor_efficiency=F('mechanical_power_w') / F('electrical_power_w'))


class DataSample(models.Model):
    powertrain = models.ForeignKey(Powertrain, on_delete=models.CASCADE, related_name='data')
    time_s = models.FloatField()
    voltage_v = models.FloatField(blank=True, null=True)
    current_a = models.FloatField(blank=True, null=True)
    rotation_speed_rad_per_s = models.FloatField(blank=True, null=True)
    torque_nm = models.FloatField(blank=True, null=True)
    thrust_n = models.FloatField(blank=True, null=True)

    objects = models.Manager()
    derived = DerivedDataManager()

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['powertrain', 'time_s'], name='unique temporal sample')
        ]

问题

我能够将“派生”测量值(如electrical_power_w)添加到数据的每一行,但我不知道如何添加将多个传动系统的数据组合在同一基准中的派生测量值:

假设 3 个动力系统,每个都有自己的电压和电流数据,我该怎么做:

Total_power = powertrain1.power + powertrain2.power + powertrain3.power

对于每个单独的时间戳(time_s)?仅当对同时采集的样本进行求和时,总功率才有意义。

目标

在不加载 Django 中的所有数据库数据的情况下,考虑到一些业务逻辑,我最终希望获得最大总功率方面的 5 个顶级基准:

我想重新创建此表,但附加了额外的列,例如“最大推力”等...该表是从数据库本身内部分页的。

标签: djangodjango-modelsdjango-ormdjango-aggregationdjango-annotate

解决方案


嗯,这是一个相当棘手的导航。我将首先添加以下注释模型方法:

from django.db.models import Sum

我想那将是添加的情况:

.annotate(total_power=Sum(electrical_power_w))

但我认为问题在于您的每一行都DerivedDataManager queryset代表一个,而该行又通过该字段DataSample链接到一个。PowertrainForeignKey

最好在业务逻辑层执行此操作,按动力总成的 UUID 分组(您需要将其添加到Powertrain模型中 - 请参阅https://docs.djangoproject.com/en/3.0/ref/models/fields/# uuidfield了解如何使用它的详细信息。然后,因为您已分组,您可以将Sum注释应用于queryset.

所以,我认为你想沿着这条路导航:

DataSample.objects.order_by(
    'powertrain'
).aggregate(
    total_price=Sum('electrical_power_w')
)

推荐阅读