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