Как использовать функцию базы данных Postgres с набором запросов Django?

У меня есть проект django, в котором в режиме реального времени хранятся данные нескольких устройств. Для этого я использовал timescaledb , который подходит для временных рядов и основан на postgres. Timescale предлагает несколько гиперфункций , которые мне нужно использовать (в частности, lttb, которая используется для понижения дискретизации данных).

Например, это один из запросов, которых я хочу достичь:

SELECT time as timestamp, value as value, %s as device_id 
FROM unnest((SELECT lttb(timestamp, value, %s) 
FROM core_devicedata where device_id=%s and timestamp between %s and %s))

Я могу получить результат этого запроса в виде необработанного запроса, заданного:

for data in DeviceData.objects.raw(query):
    ...

Я уже пробовал необработанные SQL-запросы с использованием Django. Они работают. Дело в том, что они не предлагают функций фильтрации и упорядочивания, поскольку не возвращают фактический набор запросов. Вместо этого они возвращают необработанный набор запросов. Чего я пытаюсь достичь, так это запустить запрос, как показано ниже, используя только возможности djagno orm.

SELECT time as timestamp, value as value, %s as device_id 
FROM unnest((SELECT lttb(timestamp, value, %s) 

Какие-либо предложения? Если нет возможности сделать это с помощью самого django orm, помогите мне написать метод модульного менеджера для этого способа? Как будто я должен иметь возможность фильтровать или заказывать, только если захочу.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
95
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Джанго или нет, но я предполагаю, что вы можете отключить его встраивание. Давайте посмотрим пример:

select lttb(time,price,5)->unnest() from crypto_ticks where symbol = 'BTC/USD' and time > now() - interval '1 month';
              ?column?
------------------------------------
 ("2024-04-09 13:23:29+00",70431)
 ("2024-04-17 16:08:07+00",59714.9)
 ("2024-04-22 23:15:59+00",67228.5)
 ("2024-05-01 08:24:03+00",56534.5)
 ("2024-05-07 14:37:03+00",63190.8)
(5 rows)

Теперь давайте добавим символ и сгруппируем его.

tsdb=> select symbol, lttb(time,price,5)->unnest() from crypto_ticks where symbol = 'BTC/USD' and time > now() - interval '1 month' group by 1;
 symbol  |              ?column?
---------+------------------------------------
 BTC/USD | ("2024-04-09 13:23:29+00",70431)
 BTC/USD | ("2024-04-17 16:08:07+00",59714.9)
 BTC/USD | ("2024-04-22 23:15:59+00",67228.5)
 BTC/USD | ("2024-05-01 08:24:03+00",56534.5)
 BTC/USD | ("2024-05-07 14:37:38+00",63266.6)
(5 rows)

Теперь давайте отменим вложение значений с помощью ().*

tsdb=> select symbol, (lttb(time,price,5)->unnest()).* from crypto_ticks where symbol = 'BTC/USD' and time > now() - interval '1 month' group by 1;
 symbol  |          time          |  value
---------+------------------------+---------
 BTC/USD | 2024-04-09 13:23:29+00 |   70431
 BTC/USD | 2024-04-17 16:08:07+00 | 59714.9
 BTC/USD | 2024-04-22 23:15:59+00 | 67228.5
 BTC/USD | 2024-05-01 08:24:03+00 | 56534.5
 BTC/USD | 2024-05-07 14:37:38+00 | 63266.6

Хотя это не совсем то, что я ищу, но это действительно полезный ответ для изучения новых вещей. Спасибо.

thisisjab 07.05.2024 17:59
Ответ принят как подходящий

Мой первый совет: ORM поможет вам только до определенного момента. Когда ситуация начинает усложняться, лучше всего пойти по пути необработанных запросов, иначе вы потратите больше времени на борьбу с ORM, чем на решение реальных бизнес-задач.

Вы можете добавить фильтрацию и упорядочение к необработанному запросу с помощью предложений WHERE и ORDER BY.

Вы можете писать собственные функции ORM SQL с помощью выражений Func() . Вы можете увидеть несколько примеров функций timescaledb, написанных для Django, в данном случае time_bucket, в репозитории библиотеки django-timescale.

Вы можете определить функцию примерно так (это не работает):

class LTTB(Func):
    arity = 3
    function = "lttb"
    template = "(%(function)s(%(expressions)s)->unnest()).*"

Проблема в том, что пользовательские функции требуют выходного_поля, поскольку unnest возвращает 2 дополнительных столбца, я не знаю, поддерживает ли это Django ORM.

Спасибо за Ваш ответ. Тогда я продолжу необработанный sql.

thisisjab 08.05.2024 13:35

Другие вопросы по теме