Django:将查询结果分为多个常见元素列表

时间:2019-03-20 15:11:10

标签: python django foreign-keys django-queryset

编辑:添加了所有相关模型。添加了说明。

我必须查询一个名为 Data 的表,但不是只返回一个列表,而是可能从查询中返回几个列表。否则,获取queryset结果并将其分成具有公共 SensorParameter 字段的对象数组。

我有模型数据

class Data(models.Model):
    sensor_param = models.ForeignKey(SensorParameter, on_delete=models.CASCADE)
    time = models.DateTimeField(db_index=True)
    value = models.FloatField()

并且模型 SensorParameter 具有参数(温度,振动等)和传感器实例(序列号等)的链接:

class SensorParameter(models.Model):
    sensor = models.ForeignKey(Sensor)
    parameter = models.ForeignKey(Parameter)

并为参数建模(一个容器,用于容纳不同传感器可以测量的不同类型的参数):

class Parameter(models.Model):
    parameter_name          = models.CharField(max_length=50)
    parameter_unit          = models.CharField(max_length=20, blank=True)

最后是将所有其他元素联系在一起的 Sensor 模型:

class Sensor(models.Model):
    name            = models.CharField(max_length=50, null=False, blank=True)
    serial_number   = models.CharField(max_length=50)
    sensor_type     = models.ForeignKey(SensorType)

我可以通过两次向后查找并按我想要的方式对结果查询进行排序,从而从特定的传感器中查询特定时间范围内的 Data 表。首先按 sensor_parameter 细分,然后按 time 细分我的列表:

sensor = Sensor.objects.get(serial_number=request["data_source"])
range_period = [request['start'], request['end']]
# This is the queryset I have now, though it's not set in stone
data_query = Data.objects.filter(sensor_parameter__sensor=sensor, time__range=range_period).order_by('sensor_parameter', 'time')

这会在一个大列表中得出请求的时间段和请求的传感器的所有数据点的列表。

然后如何将结果列表分为具有公共 SensorParameter 字段的对象的几个列表(或数组)?

示例来自

queryset_overall_result =
[
    {data_point_1: sensor: X, sensor_parameter: temp, value: 188, time: 00:01}
    {data_point_2: sensor: X, sensor_parameter: vibration, value: 5, time: 00:01}
    {data_point_3: sensor: X, sensor_parameter: temp, value: 185, time: 00:02}
    {data_point_4: sensor: X, sensor_parameter: vibration, value: 6, time: 00:02}
]

收件人:

list_temp =
[
    {data_point_1: sensor: X, sensor_parameter: temp, value: 188, time: 00:01}
    {data_point_3: sensor: X, sensor_parameter: temp, value: 185, time: 00:02}
]

list_vibration = 
[
    {data_point_2: sensor: X, sensor_parameter: vibration, value: 5, time: 00:01}
    {data_point_4: sensor: X, sensor_parameter: vibration, value: 6, time: 00:02}
]

是否有更好的方法来查询数据表,以便在过滤到另一个表时按时间排列给我几个列表? (SensorParameter)

还是拥有整体查询集结果,请使用python将其分解为多个常见对象元素列表?数组是理想的选择,但不确定如何实现。

理想场景:

array = 
[
    [
        {data_point_1: sensor: X, sensor_parameter: temp, value: 188, time: 00:01}
        {data_point_3: sensor: X, sensor_parameter: temp, value: 185, time: 00:02}
    ]
,
   [
        {data_point_2: sensor: X, sensor_parameter: vibration, value: 5, time: 00:01}
        {data_point_4: sensor: X, sensor_parameter: vibration, value: 6, time: 00:02}
    ]
]

约束:我不知道 Sensor 可以测量多少个或哪个 SensorParameters ,取决于 Sensor_sensor_type < / strong>。我需要尽量减少查询,因为此查询可能返回大量数据,并且可能快速连续多次发生。 DB命中次数越少越好。

2 个答案:

答案 0 :(得分:1)

所有传感器和参数以及sensor_parameters都在旋转,但我会尝试一下。如果要按SensorParameter对结果进行分组,则默认方法是查询该模型:

qs = (SensorParameter.objects
    .filter(sensor=sensor, data__time__range=range_period)
    .select_related('sensor', 'parameter')
    .distinct()
    .order_by('sensor_parameter'))

由于要访问按时间排序的相关Data对象,因此应发出适当的prefetch_related命令:

from django.db.models import Prefetch
sorted_data_qs = (Data.objects
    .filter(time__range=range_period)
    .order_by('time'))
prefetch = Prefetch('data_set', queryset=sorted_data_qs)
qs = qs.prefetch_related(prefetch) #  using qs from above

现在只有两个SQL查询,您就可以将所有数据按SensorParameter分组到单个SensorParameter对象中。您可以按以下方式访问各个数据行:

for rs in qs:
    for d in rs.data_set.all():
        print(rs.sensor.name, rs.parameter.name, d.value, d.time)

当然,在构造对象时会有一些开销。如果您不需要它们,而只需要数据行,则可以采用另一种方法:

获取满足过滤条件的所有SensorParameter的列表,然后对所有这些查询运行单个查询,以最初的构想返回可放入列表的字典:

sensor_params = (SensorParameter.objects
    .filter(sensor=sensor, data__time__range=range_period)
    .value_list('id', flat=True))

result_list = []
for sp in sensor_params:
    param_results = list(
        Data.objects
        .filter(sensor_parameter=sp, time__range=range_period)
        .order_by('time')
        .values(
            'sensor_parameter__sensor__name',
            'sensor_parameter__parameter__name',
            'value',
            'time'
        )
    )
    result_list.append(param_results)

这将导致更多查询(传感器计数加1),但这并不意味着它一定比第一种方法慢(甚至可能更快)。再次,分组是在数据库中完成的,而不是在Python中完成的。

答案 1 :(得分:0)

使用列表理解并将它们组合成列表

sensors = Sensor.objects.all()

array = []

for sensor in sensors:
    list_param = [d for d in data_query if d['sensor_parameter'] == sensor]
    array.append(list_param)