Django: разбить результат запроса на несколько списков общих элементов - PullRequest
0 голосов
/ 20 марта 2019

РЕДАКТИРОВАТЬ : добавлены все соответствующие модели.Добавлено пояснение.

Мне нужно запросить таблицу с именем Данные , но вместо того, чтобы возвращать только 1 список, возможно, несколько запросов возвращаются из запроса.В противном случае возьмите результат запроса и разбейте его на массив объектов с общими 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 , выполнив двойной обратный поиск и упорядочив полученный запрос так, как я хотел бы, чтобы мои списки были разбитывниз, сначала на датчик_параметра , затем на время :

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}
    ]
]

Ограничения: я не знаю, сколько или каких SensorParameters Sensor может измерять, это может быть от 4 до 45ish в зависимости от Sensor_sensor_type .Мне нужно попытаться свести запросы к минимуму, так как этот запрос может вернуть тонну данных и может произойти много раз в быстрой последовательности.Чем меньше БД, тем лучше.

Ответы [ 2 ]

1 голос
/ 20 марта 2019

Все датчики, параметры и параметры датчика заставляют мою голову кружиться, но я попробую. Если вы хотите сгруппировать результаты по 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.

0 голосов
/ 20 марта 2019

Используйте понимание списка и объедините их в список

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)
...