
GROUP_CONCAT for Django ORM

Aggregate functions in Django ORM are cool. This circumstance was the reason to add one more =)
Next, we will talk about a mysql-specific function
GROUP_CONCAT
and The functional that interests us is in two modules,
django.db.models.aggregates
and django.db.models.sql.aggregates
. So the scene is models.py:from django.db import models ## aggregate functions ## from django.db.models.aggregates import Aggregate # definition from django.db.models.sql.aggregates import Aggregate as SQLAggregate # implementation
Let's start with the most interesting - the actual implementation.
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)
There is (at least) one ugly thing - passing
models.DecimalField()
to the parent constructor; this is necessary so that subsequently the result of the work of our function is not erroneously converted to a numerical type (!). This code will break when you next update the Django trunk or not, we will see after the next update of the Django trunk. You have been warned. The implementation is ready, let's move on to the boring definition of a function:
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
It remains to make sure that our work works:
>>> 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'}]
The first post on Habré, uiii!