diff --git a/django/db/models/functions.py b/django/db/models/functions.py index f16cf10b15..610ecb6985 100644 --- a/django/db/models/functions.py +++ b/django/db/models/functions.py @@ -110,13 +110,13 @@ class Substr(Func): pos: an integer > 0, or an expression returning an integer length: an optional number of characters to return """ - if not hasattr('pos', 'resolve_expression'): + if not hasattr(pos, 'resolve_expression'): if pos < 1: raise ValueError("'pos' must be greater than 0") pos = Value(pos) expressions = [expression, pos] if length is not None: - if not hasattr('length', 'resolve_expression'): + if not hasattr(length, 'resolve_expression'): length = Value(length) expressions.append(length) super(Substr, self).__init__(*expressions, **extra) diff --git a/tests/db_functions/tests.py b/tests/db_functions/tests.py index 00a5e258de..97d32d86e7 100644 --- a/tests/db_functions/tests.py +++ b/tests/db_functions/tests.py @@ -278,6 +278,18 @@ class FunctionTests(TestCase): with six.assertRaisesRegex(self, ValueError, "'pos' must be greater than 0"): Author.objects.annotate(raises=Substr('name', 0)) + def test_substr_with_expressions(self): + Author.objects.create(name='John Smith', alias='smithj') + Author.objects.create(name='Rhonda') + authors = Author.objects.annotate(name_part=Substr('name', V(5), V(3))) + self.assertQuerysetEqual( + authors.order_by('name'), [ + ' Sm', + 'da', + ], + lambda a: a.name_part + ) + def test_nested_function_ordering(self): Author.objects.create(name='John Smith') Author.objects.create(name='Rhonda Simpson', alias='ronny')