mirror of
https://github.com/django/django.git
synced 2025-03-31 19:46:42 +00:00
Refs #25759 -- Documented customizing expressions' SQL on other databases.
This commit is contained in:
parent
baa8b0ec39
commit
5ca08f7cab
@ -261,6 +261,28 @@ The ``Func`` API is as follows:
|
|||||||
different number of expressions, ``TypeError`` will be raised. Defaults
|
different number of expressions, ``TypeError`` will be raised. Defaults
|
||||||
to ``None``.
|
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
|
The ``*expressions`` argument is a list of positional expressions that the
|
||||||
function will be applied to. The expressions will be converted to strings,
|
function will be applied to. The expressions will be converted to strings,
|
||||||
joined together with ``arg_joiner``, and then interpolated into the ``template``
|
joined together with ``arg_joiner``, and then interpolated into the ``template``
|
||||||
@ -560,7 +582,7 @@ an ``__init__()`` method to set some attributes::
|
|||||||
class Coalesce(Expression):
|
class Coalesce(Expression):
|
||||||
template = 'COALESCE( %(expressions)s )'
|
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)
|
super(Coalesce, self).__init__(output_field=output_field)
|
||||||
if len(expressions) < 2:
|
if len(expressions) < 2:
|
||||||
raise ValueError('expressions must have at least 2 elements')
|
raise ValueError('expressions must have at least 2 elements')
|
||||||
@ -568,7 +590,6 @@ an ``__init__()`` method to set some attributes::
|
|||||||
if not hasattr(expression, 'resolve_expression'):
|
if not hasattr(expression, 'resolve_expression'):
|
||||||
raise TypeError('%r is not an Expression' % expression)
|
raise TypeError('%r is not an Expression' % expression)
|
||||||
self.expressions = expressions
|
self.expressions = expressions
|
||||||
self.extra = extra
|
|
||||||
|
|
||||||
We do some basic validation on the parameters, including requiring at least
|
We do some basic validation on the parameters, including requiring at least
|
||||||
2 columns or values, and ensuring they are expressions. We are requiring
|
2 columns or values, and ensuring they are expressions. We are requiring
|
||||||
@ -588,22 +609,30 @@ expressions::
|
|||||||
|
|
||||||
Next, we write the method responsible for generating the SQL::
|
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 = [], []
|
sql_expressions, sql_params = [], []
|
||||||
for expression in self.expressions:
|
for expression in self.expressions:
|
||||||
sql, params = compiler.compile(expression)
|
sql, params = compiler.compile(expression)
|
||||||
sql_expressions.append(sql)
|
sql_expressions.append(sql)
|
||||||
sql_params.extend(params)
|
sql_params.extend(params)
|
||||||
self.extra['expressions'] = ','.join(sql_expressions)
|
template = template or self.template
|
||||||
return self.template % self.extra, sql_params
|
data = {'expressions': ','.join(sql_expressions)}
|
||||||
|
return template % data, params
|
||||||
|
|
||||||
def as_oracle(self, compiler, connection):
|
def as_oracle(self, compiler, connection):
|
||||||
"""
|
"""
|
||||||
Example of vendor specific handling (Oracle in this case).
|
Example of vendor specific handling (Oracle in this case).
|
||||||
Let's make the function name lowercase.
|
Let's make the function name lowercase.
|
||||||
"""
|
"""
|
||||||
self.template = 'coalesce( %(expressions)s )'
|
return self.as_sql(compiler, connection, template='coalesce( %(expressions)s )')
|
||||||
return self.as_sql(compiler, connection)
|
|
||||||
|
``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
|
We generate the SQL for each of the ``expressions`` by using the
|
||||||
``compiler.compile()`` method, and join the result together with commas.
|
``compiler.compile()`` method, and join the result together with commas.
|
||||||
|
@ -94,6 +94,11 @@ following methods:
|
|||||||
``compiler.compile(expression)`` should be used. The ``compiler.compile()``
|
``compiler.compile(expression)`` should be used. The ``compiler.compile()``
|
||||||
method will take care of calling vendor-specific methods of the expression.
|
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)
|
.. method:: as_vendorname(self, compiler, connection)
|
||||||
|
|
||||||
Works like ``as_sql()`` method. When an expression is compiled by
|
Works like ``as_sql()`` method. When an expression is compiled by
|
||||||
|
Loading…
x
Reference in New Issue
Block a user