Fixed #23460 -- Added literal `%s` support to extra() QuerySets.
This commit is contained in:
parent
17557d068c
commit
ef5f9b6ae8
|
@ -1775,6 +1775,7 @@ class Query(object):
|
||||||
entry_params = []
|
entry_params = []
|
||||||
pos = entry.find("%s")
|
pos = entry.find("%s")
|
||||||
while pos != -1:
|
while pos != -1:
|
||||||
|
if pos == 0 or entry[pos - 1] != '%':
|
||||||
entry_params.append(next(param_iter))
|
entry_params.append(next(param_iter))
|
||||||
pos = entry.find("%s", pos + 2)
|
pos = entry.find("%s", pos + 2)
|
||||||
select_pairs[name] = (entry, entry_params)
|
select_pairs[name] = (entry, entry_params)
|
||||||
|
|
|
@ -1144,11 +1144,12 @@ of the arguments is required, but you should use at least one of them.
|
||||||
select=OrderedDict([('a', '%s'), ('b', '%s')]),
|
select=OrderedDict([('a', '%s'), ('b', '%s')]),
|
||||||
select_params=('one', 'two'))
|
select_params=('one', 'two'))
|
||||||
|
|
||||||
The only thing to be careful about when using select parameters in
|
If you need to use a literal ``%s`` inside your select string, use
|
||||||
``extra()`` is to avoid using the substring ``"%%s"`` (that's *two*
|
the sequence ``%%s``.
|
||||||
percent characters before the ``s``) in the select strings. Django's
|
|
||||||
tracking of parameters looks for ``%s`` and an escaped ``%`` character
|
.. versionchanged:: 1.8
|
||||||
like this isn't detected. That will lead to incorrect results.
|
|
||||||
|
Prior to 1.8, you were unable to escape a literal ``%s``.
|
||||||
|
|
||||||
* ``where`` / ``tables``
|
* ``where`` / ``tables``
|
||||||
|
|
||||||
|
|
|
@ -281,6 +281,9 @@ Models
|
||||||
Django uses whenever objects are loaded using the ORM. The method allows
|
Django uses whenever objects are loaded using the ORM. The method allows
|
||||||
customizing model loading behavior.
|
customizing model loading behavior.
|
||||||
|
|
||||||
|
* ``extra(select={...})`` now allows you to escape a literal ``%s`` sequence
|
||||||
|
using ``%%s``.
|
||||||
|
|
||||||
Signals
|
Signals
|
||||||
^^^^^^^
|
^^^^^^^
|
||||||
|
|
||||||
|
|
|
@ -1655,6 +1655,21 @@ class Queries5Tests(TestCase):
|
||||||
['<Note: n1>', '<Note: n2>']
|
['<Note: n1>', '<Note: n2>']
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_extra_select_literal_percent_s(self):
|
||||||
|
# Allow %%s to escape select clauses
|
||||||
|
self.assertEqual(
|
||||||
|
Note.objects.extra(select={'foo': "'%%s'"})[0].foo,
|
||||||
|
'%s'
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
Note.objects.extra(select={'foo': "'%%s bar %%s'"})[0].foo,
|
||||||
|
'%s bar %s'
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
Note.objects.extra(select={'foo': "'bar %%s'"})[0].foo,
|
||||||
|
'bar %s'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SelectRelatedTests(TestCase):
|
class SelectRelatedTests(TestCase):
|
||||||
def test_tickets_3045_3288(self):
|
def test_tickets_3045_3288(self):
|
||||||
|
|
Loading…
Reference in New Issue