Как запросить кортежи столбцов в запросах к базе данных Django? - PullRequest
0 голосов
/ 28 марта 2020

У меня есть таблица ports(switch_ip, slot_number, port_number, many, more, columns), и я хотел бы выполнить следующий запрос PostgreSQL, используя Django:

SELECT switch_ip, array_agg((slot_number, port_number, many, more, columns) ORDER BY slot_number, port_number) info
FROM ports
GROUP BY switch_ip
ORDER BY switch_ip

Используя django.contrib.postgres.aggregates, вот что я получил так далеко:

Port.objects \
    .values('switch_ip') \
    .annotate(
        info=ArrayAgg('slot_number', ordering=('slot_number', 'port_number'))
    ) \
    .order_by('switch_ip')

Я не могу включить более одного столбца в ArrayAgg. Ни один из ArrayAgg(a, b, c), ArrayAgg((a, b, c)), ArrayAgg([a, b, c]), кажется, не работает. Обходной путь может включать отдельные ArrayAgg s для каждого столбца и каждый с одинаковым порядком. Я бы презирал это, потому что у меня много столбцов. Есть ли более приятный обходной путь, возможно, более низкоуровневый?

Я подозреваю, что это не проблема с самим ArrayAgg, а скорее с выражениями кортежей в целом. Можно ли вообще иметь кортежи в Django запросах? Например, что было бы соответствующим Django из:

SELECT switch_ip, (slot_number, port_number, many, more, columns) info
FROM ports

Если это еще не возможно в Django, насколько осуществимым было бы это реализовать?

1 Ответ

0 голосов
/ 31 марта 2020

Проведя немного больше исследований, я думаю, можно добавить отсутствующую функциональность кортежа следующим образом:

  1. Создать новый тип поля модели с именем TupleField. Реализация может выглядеть примерно так: django.contrib.postgres.fields.ArrayField. TupleField было бы довольно неудобно, потому что я не думаю, что какая-либо СУБД допускает использование составных типов в качестве типов столбцов, поэтому использование TupleField будет ограничено (возможно, промежуточными?) Результатами запроса.
  2. Создать новый подкласс django.db.models.Expression, который оборачивает несколько выражений сам по себе (как, например, Func в целом, так что рассмотрение реализации Func может оказаться полезным) и оценивается как TupleField. Например, назовите этот подкласс TupleExpression.

Тогда я мог бы просто аннотировать ArrayAgg(TupleExpression('slot_number', 'port_number', 'many', 'more', 'columns'), ordering=('slot_number', 'port_number')), чтобы решить мою исходную проблему. Это аннотирует каждый switch_ip правильно упорядоченными массивами кортежей, где каждый кортеж представляет один порт коммутатора.

...