Fixed #32231 -- Allowed passing None params to QuerySet.raw().

This commit is contained in:
Alexander Lyabah 2020-11-28 18:08:27 +02:00 committed by Mariusz Felisiak
parent aa3d360631
commit 415f50298f
5 changed files with 28 additions and 7 deletions

View File

@ -818,7 +818,7 @@ class QuerySet:
# PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
##################################################
def raw(self, raw_query, params=None, translations=None, using=None):
def raw(self, raw_query, params=(), translations=None, using=None):
if using is None:
using = self.db
qs = RawQuerySet(raw_query, model=self.model, params=params, translations=translations, using=using)
@ -1419,14 +1419,14 @@ class RawQuerySet:
Provide an iterator which converts the results of raw SQL queries into
annotated model instances.
"""
def __init__(self, raw_query, model=None, query=None, params=None,
def __init__(self, raw_query, model=None, query=None, params=(),
translations=None, using=None, hints=None):
self.raw_query = raw_query
self.model = model
self._db = using
self._hints = hints or {}
self.query = query or sql.RawQuery(sql=raw_query, using=self.db, params=params)
self.params = params or ()
self.params = params
self.translations = translations or {}
self._result_cache = None
self._prefetch_related_lookups = ()

View File

@ -69,8 +69,8 @@ JoinInfo = namedtuple(
class RawQuery:
"""A single raw SQL query."""
def __init__(self, sql, using, params=None):
self.params = params or ()
def __init__(self, sql, using, params=()):
self.params = params
self.sql = sql
self.using = using
self.cursor = None
@ -111,9 +111,13 @@ class RawQuery:
@property
def params_type(self):
if self.params is None:
return None
return dict if isinstance(self.params, Mapping) else tuple
def __str__(self):
if self.params_type is None:
return self.sql
return self.sql % self.params_type(self.params)
def _execute_query(self):
@ -127,6 +131,8 @@ class RawQuery:
params = tuple(adapter(val) for val in self.params)
elif params_type is dict:
params = {key: adapter(val) for key, val in self.params.items()}
elif params_type is None:
params = None
else:
raise RuntimeError("Unexpected params type: %s" % params_type)

View File

@ -1843,7 +1843,7 @@ raised if ``select_for_update()`` is used in autocommit mode.
``raw()``
~~~~~~~~~
.. method:: raw(raw_query, params=None, translations=None)
.. method:: raw(raw_query, params=(), translations=None)
Takes a raw SQL query, executes it, and returns a
``django.db.models.query.RawQuerySet`` instance. This ``RawQuerySet`` instance
@ -1858,6 +1858,11 @@ See the :doc:`/topics/db/sql` for more information.
filtering. As such, it should generally be called from the ``Manager`` or
from a fresh ``QuerySet`` instance.
.. versionchanged:: 3.2
The default value of the ``params`` argument was changed from ``None`` to
an empty tuple.
Operators that return new ``QuerySet``\s
----------------------------------------

View File

@ -43,7 +43,7 @@ Performing raw queries
The ``raw()`` manager method can be used to perform raw SQL queries that
return model instances:
.. method:: Manager.raw(raw_query, params=None, translations=None)
.. method:: Manager.raw(raw_query, params=(), translations=None)
This method takes a raw SQL query, executes it, and returns a
``django.db.models.query.RawQuerySet`` instance. This ``RawQuerySet`` instance
@ -99,6 +99,11 @@ make it very powerful.
both rows will match. To prevent this, perform the correct typecasting
before using the value in a query.
.. versionchanged:: 3.2
The default value of the ``params`` argument was changed from ``None`` to
an empty tuple.
Mapping query fields to model fields
------------------------------------

View File

@ -180,6 +180,11 @@ class RawQueryTests(TestCase):
self.assertEqual(len(results), 1)
self.assertIsInstance(repr(qset), str)
def test_params_none(self):
query = "SELECT * FROM raw_query_author WHERE first_name like 'J%'"
qset = Author.objects.raw(query, params=None)
self.assertEqual(len(qset), 2)
def test_escaped_percent(self):
query = "SELECT * FROM raw_query_author WHERE first_name like 'J%%'"
qset = Author.objects.raw(query)