Django Framework

индекс
177,05

GROUP_CONCAT для Django ORM


Агрегатные функции в Django ORM — крутые. Это обстоятельство послужило поводом добавить еще одну =)

Далее речь пойдет о mysql-специфичной функции GROUP_CONCAT и волшебных розовых пони, как на картинке django-trunk.


Интересующий нас функционал находится в двух модулях, django.db.models.aggregates и django.db.models.sql.aggregates. Итак, место действия — models.py:

from django.db import models
## агрегатные функции ##
from django.db.models.aggregates import Aggregate # определение
from django.db.models.sql.aggregates import Aggregate as SQLAggregate # реализация


Начнем с самого интересного — собственно реализации.

class SQLConcat(SQLAggregate):
    sql_function = "GROUP_CONCAT"
    
    def __init__(self, col, separator=',', **extra):
        self.sql_template = "%%(function)s(%%(field)s SEPARATOR '%s')" % separator
        super(SQLConcat, self).__init__(col, source=models.DecimalField(), **extra)


Здесь есть (как минимум) одна некрасивая штука — передача models.DecimalField() в конструктор родителя; это необходимо для того, чтобы впоследствии результат работы нашей функции не был ошибочно приведен к числовому типу (!). Сломается этот код при очередном обновлении транка Django или нет, мы увидим после очередного обновления транка Django. You have been warned.

Реализации готова, перейдем к скучному определению функции:

class Concat(Aggregate):
    name = "Concat"
    
    def add_to_query(self, query, alias, col, source, is_summary):
        aggregate = SQLConcat(col, is_summary=is_summary, **self.extra)
        query.aggregates[alias] = aggregate


Осталось удостовериться, что наше произведение работает:

>>> Post.threads.aggregate(Concat('id'))

{'id__concat': '1,2,3,4'}

>>> from django.db import connection
>>> connection.queries

[{'sql': u"SELECT GROUP_CONCAT(`main_post`.`id` SEPARATOR ',') AS `id__concat` FROM `main_post`",
  'time': '0.000'}]


Первый пост на Хабре, уиии!
+29
11 марта 2010, 02:34
24

комментарии (8)

–5
Nyaon #
Open your eyes I see
Your eyes are open
+1
zloy_alu #
Магия — это не хорошо, но впечетляет)
+2
shemsu #
Спасибо, очень интересно!
НЛО прилетело и опубликовало эту надпись здесь
+5
angry_elf #
Похпапе головного мозга?

Это расширение уже существующего ORM'а для получения нужной функциональности без написания своего SQL.
+1
alarin #
Ага, и только по SQL92 стандарту )))

Дорогой, yazy, для каждой задачи свои инструменты. И здесь речь шла об инструменте )
НЛО прилетело и опубликовало эту надпись здесь
0
alarin #
Тут же автор задействует функцию спецефичную для СУБД

Да, использование специфичных функций СУБД, конечно плохо, НО только в том случае если проект достаточно большой и возможен переход на другую СУБД.

К слову, функция GROUP_CONCAT и сама по себе ужасна, в плане скорости работы. Но! Как я уже сказал — эта статья о конкретном инструменте, во всяком случае, мне так показалось. Не надо так резко критиковать автора — человек старался, писал )))

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.