Refs #25629 -- Added `arity` class attribute to `Func` expressions
This commit is contained in:
parent
03c6ad7ad4
commit
0a26121797
|
@ -482,8 +482,18 @@ class Func(Expression):
|
||||||
function = None
|
function = None
|
||||||
template = '%(function)s(%(expressions)s)'
|
template = '%(function)s(%(expressions)s)'
|
||||||
arg_joiner = ', '
|
arg_joiner = ', '
|
||||||
|
arity = None # The number of arguments the function accepts.
|
||||||
|
|
||||||
def __init__(self, *expressions, **extra):
|
def __init__(self, *expressions, **extra):
|
||||||
|
if self.arity is not None and len(expressions) != self.arity:
|
||||||
|
raise TypeError(
|
||||||
|
"'%s' takes exactly %s %s (%s given)" % (
|
||||||
|
self.__class__.__name__,
|
||||||
|
self.arity,
|
||||||
|
"argument" if self.arity == 1 else "arguments",
|
||||||
|
len(expressions),
|
||||||
|
)
|
||||||
|
)
|
||||||
output_field = extra.pop('output_field', None)
|
output_field = extra.pop('output_field', None)
|
||||||
super(Func, self).__init__(output_field=output_field)
|
super(Func, self).__init__(output_field=output_field)
|
||||||
self.source_expressions = self._parse_expressions(*expressions)
|
self.source_expressions = self._parse_expressions(*expressions)
|
||||||
|
|
|
@ -145,9 +145,6 @@ class Lower(Transform):
|
||||||
function = 'LOWER'
|
function = 'LOWER'
|
||||||
lookup_name = 'lower'
|
lookup_name = 'lower'
|
||||||
|
|
||||||
def __init__(self, expression, **extra):
|
|
||||||
super(Lower, self).__init__(expression, **extra)
|
|
||||||
|
|
||||||
|
|
||||||
class Now(Func):
|
class Now(Func):
|
||||||
template = 'CURRENT_TIMESTAMP'
|
template = 'CURRENT_TIMESTAMP'
|
||||||
|
@ -197,6 +194,3 @@ class Substr(Func):
|
||||||
class Upper(Transform):
|
class Upper(Transform):
|
||||||
function = 'UPPER'
|
function = 'UPPER'
|
||||||
lookup_name = 'upper'
|
lookup_name = 'upper'
|
||||||
|
|
||||||
def __init__(self, expression, **extra):
|
|
||||||
super(Upper, self).__init__(expression, **extra)
|
|
||||||
|
|
|
@ -123,10 +123,7 @@ class Transform(RegisterLookupMixin, Func):
|
||||||
first examine self and then check output_field.
|
first examine self and then check output_field.
|
||||||
"""
|
"""
|
||||||
bilateral = False
|
bilateral = False
|
||||||
|
arity = 1
|
||||||
def __init__(self, expression, **extra):
|
|
||||||
# Restrict Transform to allow only a single expression.
|
|
||||||
super(Transform, self).__init__(expression, **extra)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lhs(self):
|
def lhs(self):
|
||||||
|
|
|
@ -252,6 +252,15 @@ The ``Func`` API is as follows:
|
||||||
A class attribute that denotes the character used to join the list of
|
A class attribute that denotes the character used to join the list of
|
||||||
``expressions`` together. Defaults to ``', '``.
|
``expressions`` together. Defaults to ``', '``.
|
||||||
|
|
||||||
|
.. attribute:: arity
|
||||||
|
|
||||||
|
.. versionadded:: 1.10
|
||||||
|
|
||||||
|
A class attribute that denotes the number of arguments the function
|
||||||
|
accepts. If this attribute is set and the function is called with a
|
||||||
|
different number of expressions, ``TypeError`` will be raised. Defaults
|
||||||
|
to ``None``.
|
||||||
|
|
||||||
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``
|
||||||
|
|
|
@ -175,6 +175,10 @@ Models
|
||||||
accessible as a descriptor on the proxied model class and may be referenced in
|
accessible as a descriptor on the proxied model class and may be referenced in
|
||||||
queryset filtering.
|
queryset filtering.
|
||||||
|
|
||||||
|
* The :attr:`~django.db.models.Func.arity` class attribute is added to
|
||||||
|
:class:`~django.db.models.Func`. This attribute can be used to set the number
|
||||||
|
of arguments the function accepts.
|
||||||
|
|
||||||
Requests and Responses
|
Requests and Responses
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|
|
@ -389,6 +389,9 @@ class FunctionTests(TestCase):
|
||||||
lambda a: (a.lower_name, a.name)
|
lambda a: (a.lower_name, a.name)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
with self.assertRaisesMessage(TypeError, "'Lower' takes exactly 1 argument (2 given)"):
|
||||||
|
Author.objects.update(name=Lower('name', 'name'))
|
||||||
|
|
||||||
def test_upper(self):
|
def test_upper(self):
|
||||||
Author.objects.create(name='John Smith', alias='smithj')
|
Author.objects.create(name='John Smith', alias='smithj')
|
||||||
Author.objects.create(name='Rhonda')
|
Author.objects.create(name='Rhonda')
|
||||||
|
|
Loading…
Reference in New Issue