Django ORM LEFT JOIN在具有相同值的字段上

问题描述 投票:0回答:1

我正在为水文学家编写网络界面。水文学家应该看到这样的不同水文测量表。

+----------------+----------------------+-------+--------------------+-------------+------------------+
| observation_id | observation_datetime | level | water_temperature  |precipitation|precipitation_type|
+----------------+----------------------+-------+--------------------+-------------+------------------+

| 1 | 2019-03-11 11:00:00 | 11 | 21 | 31 |
| 2 | 2019-03-12 12:00:00 | 12 | 22 | 32 |
| 3 | 2019-03-13 13:00:00 | 13 | 23 | 33 |
| 4 | 2019-03-14 14:00:00 | 14 | 24 | 34 |

我有这些模型来描述测量

class AbstractMeasurement(model.Model):
    observation_datetime = models.DateTimeField()
    observation = models.ForeignKey(Observation, on_delete = models.DO_NOTHING)

class Meta:
    abstract = True

class Level(AbstractMeasurement):
    level = models.DecimalField()

class WaterTemperature(AbstractMeasurement):
    air_temperature = models.DecimalField()

class Precipitation(AbstractMeasurement):
    precipitation = models.DecimalField()
    precipitation_type = models.CharField()

等等

水平主要测量和测量不能没有水平。等级是基本模型。

在mysql中,我可以通过此查询来完成

    SELECT level.observation_id, 
            level.observation_datetime, 
            level.level, 
            water_temperature.water_temperature, 
            precipitation.precipitation, 
            precipitation.precipitation_type 
    FROM level 
    LEFT JOIN precipitation ON 
            level.observation_datetime = precipitation.observation_datetime 
            AND 
            level.observation_id = precipitation.observation_id 
    LEFT JOIN water_temperature ON 
            level.observation_datetime = water_temperature.observation_datetime 
            AND 
            level.observation_id = water_temperature.observation_id;

如何使用没有外键关系的模型在django中左键加入?

django django-models django-orm
1个回答
0
投票

你可以实现你想要的,但它会不必要地低效(甚至比你发布的SQL查询更多)。由于您当前的模型结构相当扭曲,如果您可以更改模型,则应该。

也就是说,这是如何带来例如Precipitation数据到你的Level查询。每个字段和行需要一个子查询:

from django.db.models import Q, OuterRef, Subquery

join_criteria = Q(
    observation_id=OuterRef('observation_id'), 
    observation_datetime = OuterRef('observation_datetime')
)

subquery_precipitation = Subquery(Precipitation.objects
    .filter(join_criteria)
    .values('precipitation')[:1])

subquery_precipitation_type = Subquery(Precipitation.objects
    .filter(join_criteria)
    .values('precipitation_type')[:1])

levels = (Level.objects
        .annotate(precipitation=subquery_precipitation)
        .annotate(precipitation_type=subquery_precipitation_type))

现在尝试将字段数乘以查询中的预期行数 - 这是需要执行的子查询数。

因此,这是一个概念证明,您可以在小桌子和几个字段中使用。它不适用于大型数据集和许多领域。你应该重新考虑你的模型。

有了合适的型号,它应该很容易实现您的需求。

© www.soinside.com 2019 - 2024. All rights reserved.