diff --git a/docs/ref/models/conditional-expressions.txt b/docs/ref/models/conditional-expressions.txt index cfdbd0790a..6dd159b361 100644 --- a/docs/ref/models/conditional-expressions.txt +++ b/docs/ref/models/conditional-expressions.txt @@ -164,6 +164,13 @@ the ``Client`` has been with us, we could do so using lookups: ... ).values_list("name", "discount") +The ``**extra`` kwargs are ``key=value`` pairs that can be interpolated +into the ``template`` attribute. To avoid an SQL injection vulnerability, +``extra`` :ref:`must not contain untrusted user input +` as these values are interpolated +into the SQL string rather than passed as query parameters, where the database +driver would escape them. + .. note:: Remember that the conditions are evaluated in order, so in the above diff --git a/docs/ref/models/expressions.txt b/docs/ref/models/expressions.txt index 1b6a208d01..ae39097c48 100644 --- a/docs/ref/models/expressions.txt +++ b/docs/ref/models/expressions.txt @@ -568,7 +568,7 @@ expressions. For more details see :doc:`conditional-expressions`. ``Subquery()`` expressions -------------------------- -.. class:: Subquery(queryset, output_field=None) +.. class:: Subquery(queryset, output_field=None, **extra) You can add an explicit subquery to a ``QuerySet`` using the ``Subquery`` expression. @@ -593,6 +593,13 @@ On PostgreSQL, the SQL looks like: ORDER BY U0."created_at" DESC LIMIT 1 ) AS "newest_commenter_email" FROM "post" +The ``**extra`` kwargs are ``key=value`` pairs that can be interpolated +into the ``template`` attribute. To avoid an SQL injection vulnerability, +``extra`` :ref:`must not contain untrusted user input +` as these values are interpolated +into the SQL string rather than passed as query parameters, where the database +driver would escape them. + .. note:: The examples in this section are designed to show how to force diff --git a/tests/expressions_case/tests.py b/tests/expressions_case/tests.py index 8704a7b991..c63cc3f252 100644 --- a/tests/expressions_case/tests.py +++ b/tests/expressions_case/tests.py @@ -722,6 +722,22 @@ class CaseExpressionTests(TestCase): transform=itemgetter("integer", "integer2", "max"), ) + def test_case_with_extra_kwargs(self): + case_expression = Case( + When(integer=1, then=Value(10)), + When(integer=2, then=Value(20)), + default=Value(0), + template="CASE %(cases)s ELSE %(default)s + 5 END", + ) + self.assertListEqual( + list( + CaseTestModel.objects.annotate(values=case_expression).values_list( + "values", flat=True + ) + ), + [10, 20, 5, 20, 5, 5, 5], + ) + def test_update(self): CaseTestModel.objects.update( string=Case(