【问题标题】:Dynamic views in Django ORM - best approach?Django ORM 中的动态视图 - 最佳方法?
【发布时间】:2020-05-24 00:05:13
【问题描述】:

一些背景

我正在考虑使用 Django 重建现有的 Laravel 网站。这是一个允许共享来自无人机/无人机推进组件的基准数据的网站。一些基准测试是在同时测试多个电机和螺旋桨时完成的,这意味着一个电池将承受多个电机的负载,但这也意味着来自一个螺旋桨的气流会影响另一个螺旋桨上捕获的数据。这意味着数据是物理耦合的。 Here is an example。现在我正在尝试构建这个项目以允许即将推出的功能,并查看 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 个动力系统,每个都有自己的电压和电流数据,我该怎么做:

总功率 = powertrain1.power + powertrain2.power + powertrain3.power

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

目标

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

  • 标记为私有的基准会被自动排除(直到授权进入)
  • 选择隐藏扭矩的基准会自动生成扭矩数据,同时所有派生的机械功率和电机效率值都变为无。

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

【问题讨论】:

    标签: django django-models django-orm django-aggregation django-annotate


    【解决方案1】:

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

    from django.db.models import Sum
    

    我想这将是一个添加的情况:

    .annotate(total_power=Sum(electrical_power_w))
    

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

    最好在业务逻辑层执行此操作,按动力总成的 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')
    )
    

    【讨论】:

    • 很好,这似乎是正确的方向。根据您的回答,我尝试了: DataSample.derived.values('powertrain__benchmark','time_s').annotate(total_power=Sum('electrical_power_w')).order_by('total_power') 这几乎可以满足我的需求。现在我需要提取每个时间戳的最大总功率。
    • @theKnack 太棒了,我可以进一步推动你。你的数据结构是什么样的?愿意为此提供帮助吗?
    • @[Wind Up Lord Vexxos] 我使用 Django Admin 手动创建了一些数据,是否有推荐的方法来共享这些数据,也许使用种子脚本?
    猜你喜欢
    • 1970-01-01
    • 2012-09-22
    • 2015-11-12
    • 1970-01-01
    • 2021-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多