Loading docs/ref/models/expressions.txt +36 −7 Original line number Diff line number Diff line Loading @@ -261,6 +261,28 @@ The ``Func`` API is as follows: different number of expressions, ``TypeError`` will be raised. Defaults to ``None``. .. method:: as_sql(compiler, connection, function=None, template=None) Generates the SQL for the database function. The ``as_vendor()`` methods should use the ``function`` and ``template`` parameters to customize the SQL as needed. For example: .. snippet:: :filename: django/db/models/functions.py class ConcatPair(Func): ... function = 'CONCAT' ... def as_mysql(self, compiler, connection): return super(ConcatPair, self).as_sql( compiler, connection, function='CONCAT_WS', template="%(function)s('', %(expressions)s)", ) The ``*expressions`` argument is a list of positional expressions that the function will be applied to. The expressions will be converted to strings, joined together with ``arg_joiner``, and then interpolated into the ``template`` Loading Loading @@ -560,7 +582,7 @@ an ``__init__()`` method to set some attributes:: class Coalesce(Expression): template = 'COALESCE( %(expressions)s )' def __init__(self, expressions, output_field, **extra): def __init__(self, expressions, output_field): super(Coalesce, self).__init__(output_field=output_field) if len(expressions) < 2: raise ValueError('expressions must have at least 2 elements') Loading @@ -568,7 +590,6 @@ an ``__init__()`` method to set some attributes:: if not hasattr(expression, 'resolve_expression'): raise TypeError('%r is not an Expression' % expression) self.expressions = expressions self.extra = extra We do some basic validation on the parameters, including requiring at least 2 columns or values, and ensuring they are expressions. We are requiring Loading @@ -588,22 +609,30 @@ expressions:: Next, we write the method responsible for generating the SQL:: def as_sql(self, compiler, connection): def as_sql(self, compiler, connection, template=None): sql_expressions, sql_params = [], [] for expression in self.expressions: sql, params = compiler.compile(expression) sql_expressions.append(sql) sql_params.extend(params) self.extra['expressions'] = ','.join(sql_expressions) return self.template % self.extra, sql_params template = template or self.template data = {'expressions': ','.join(sql_expressions)} return template % data, params def as_oracle(self, compiler, connection): """ Example of vendor specific handling (Oracle in this case). Let's make the function name lowercase. """ self.template = 'coalesce( %(expressions)s )' return self.as_sql(compiler, connection) return self.as_sql(compiler, connection, template='coalesce( %(expressions)s )') ``as_sql()`` methods can support custom keyword arguments, allowing ``as_vendorname()`` methods to override data used to generate the SQL string. Using ``as_sql()`` keyword arguments for customization is preferable to mutating ``self`` within ``as_vendorname()`` methods as the latter can lead to errors when running on different database backends. If your class relies on class attributes to define data, consider allowing overrides in your ``as_sql()`` method. We generate the SQL for each of the ``expressions`` by using the ``compiler.compile()`` method, and join the result together with commas. Loading docs/ref/models/lookups.txt +5 −0 Original line number Diff line number Diff line Loading @@ -94,6 +94,11 @@ following methods: ``compiler.compile(expression)`` should be used. The ``compiler.compile()`` method will take care of calling vendor-specific methods of the expression. Custom keyword arguments may be defined on this method if it's likely that ``as_vendorname()`` methods or subclasses will need to supply data to override the generation of the SQL string. See :meth:`Func.as_sql` for example usage. .. method:: as_vendorname(self, compiler, connection) Works like ``as_sql()`` method. When an expression is compiled by Loading Loading
docs/ref/models/expressions.txt +36 −7 Original line number Diff line number Diff line Loading @@ -261,6 +261,28 @@ The ``Func`` API is as follows: different number of expressions, ``TypeError`` will be raised. Defaults to ``None``. .. method:: as_sql(compiler, connection, function=None, template=None) Generates the SQL for the database function. The ``as_vendor()`` methods should use the ``function`` and ``template`` parameters to customize the SQL as needed. For example: .. snippet:: :filename: django/db/models/functions.py class ConcatPair(Func): ... function = 'CONCAT' ... def as_mysql(self, compiler, connection): return super(ConcatPair, self).as_sql( compiler, connection, function='CONCAT_WS', template="%(function)s('', %(expressions)s)", ) The ``*expressions`` argument is a list of positional expressions that the function will be applied to. The expressions will be converted to strings, joined together with ``arg_joiner``, and then interpolated into the ``template`` Loading Loading @@ -560,7 +582,7 @@ an ``__init__()`` method to set some attributes:: class Coalesce(Expression): template = 'COALESCE( %(expressions)s )' def __init__(self, expressions, output_field, **extra): def __init__(self, expressions, output_field): super(Coalesce, self).__init__(output_field=output_field) if len(expressions) < 2: raise ValueError('expressions must have at least 2 elements') Loading @@ -568,7 +590,6 @@ an ``__init__()`` method to set some attributes:: if not hasattr(expression, 'resolve_expression'): raise TypeError('%r is not an Expression' % expression) self.expressions = expressions self.extra = extra We do some basic validation on the parameters, including requiring at least 2 columns or values, and ensuring they are expressions. We are requiring Loading @@ -588,22 +609,30 @@ expressions:: Next, we write the method responsible for generating the SQL:: def as_sql(self, compiler, connection): def as_sql(self, compiler, connection, template=None): sql_expressions, sql_params = [], [] for expression in self.expressions: sql, params = compiler.compile(expression) sql_expressions.append(sql) sql_params.extend(params) self.extra['expressions'] = ','.join(sql_expressions) return self.template % self.extra, sql_params template = template or self.template data = {'expressions': ','.join(sql_expressions)} return template % data, params def as_oracle(self, compiler, connection): """ Example of vendor specific handling (Oracle in this case). Let's make the function name lowercase. """ self.template = 'coalesce( %(expressions)s )' return self.as_sql(compiler, connection) return self.as_sql(compiler, connection, template='coalesce( %(expressions)s )') ``as_sql()`` methods can support custom keyword arguments, allowing ``as_vendorname()`` methods to override data used to generate the SQL string. Using ``as_sql()`` keyword arguments for customization is preferable to mutating ``self`` within ``as_vendorname()`` methods as the latter can lead to errors when running on different database backends. If your class relies on class attributes to define data, consider allowing overrides in your ``as_sql()`` method. We generate the SQL for each of the ``expressions`` by using the ``compiler.compile()`` method, and join the result together with commas. Loading
docs/ref/models/lookups.txt +5 −0 Original line number Diff line number Diff line Loading @@ -94,6 +94,11 @@ following methods: ``compiler.compile(expression)`` should be used. The ``compiler.compile()`` method will take care of calling vendor-specific methods of the expression. Custom keyword arguments may be defined on this method if it's likely that ``as_vendorname()`` methods or subclasses will need to supply data to override the generation of the SQL string. See :meth:`Func.as_sql` for example usage. .. method:: as_vendorname(self, compiler, connection) Works like ``as_sql()`` method. When an expression is compiled by Loading