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


    Первый пост на Хабре, уиии!
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 8

    • НЛО прилетело и опубликовало эту надпись здесь
        +1
        Магия — это не хорошо, но впечетляет)
          +2
          Спасибо, очень интересно!
          • НЛО прилетело и опубликовало эту надпись здесь
              +5
              Похпапе головного мозга?

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

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

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

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

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

              Самое читаемое