mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	Fixed #23460 -- Added literal %s support to extra() QuerySets.
				
					
				
			This commit is contained in:
		
				
					committed by
					
						 Tim Graham
						Tim Graham
					
				
			
			
				
	
			
			
			
						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): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user