I want to filter some database objects by a concatenated string.
The normal SQL query would be:
SELECT concat(firstName, \' \', name) FROM person WHE
I solved this by implementing a custom Aggregate function. In this case I needed to concatenate individual fields into a street address to be able to filter/search for matches. The following aggregate function allows to specify a field and one or more others to perform a SQL CONCAT_WS.
Edit 3 Aug 2015:
A better implementation with details gleaned from https://stackoverflow.com/a/19529861/3230522. The previous implementation would fail if the queryset was used in a subquery. The table names are now correct, although I note that this just works for concatenation of columns from the same table.
from django.db.models import Aggregate
from django.db.models.sql.aggregates import Aggregate as SQLAggregate
class SqlAggregate(SQLAggregate):
sql_function = 'CONCAT_WS'
sql_template = u'%(function)s(" ", %(field)s, %(columns_to_concatenate)s)'
def as_sql(self, qn, connection):
self.extra['columns_to_concatenate'] = ', '.join(
['.'.join([qn(self.col[0]), qn(c.strip())]) for c in self.extra['with_columns'].split(',')])
return super(SqlAggregate, self).as_sql(qn, connection)
class Concatenate(Aggregate):
sql = SqlAggregate
def __init__(self, expression, **extra):
super(Concatenate, self).__init__(
expression,
**extra)
def add_to_query(self, query, alias, col, source, is_summary):
aggregate = self.sql(col,
source=source,
is_summary=is_summary,
**self.extra)
query.aggregates[alias] = aggregate