📜 ⬆️ ⬇️

GROUP_CONCAT for Django ORM


The aggregate functions in Django ORM are cool. This circumstance was the reason to add another =)

The following discussion focuses on the mysql-specific function. GROUP_CONCAT GROUP_CONCAT and magical pink ponies, like the django-trunk picture .


The functionality we are interested in is in two modules, django.db.models.aggregates and django.db.models.sql.aggregates . So, the scene - 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 the result of the work of our function would not be mistakenly reduced to a numeric type (!). This code will be broken at the next update of 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 the 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é, wiii!

Source: https://habr.com/ru/post/87096/


All Articles