mirror of
				https://github.com/django/django.git
				synced 2025-10-30 09:06:13 +00:00 
			
		
		
		
	[3.2.x] Fixed #32548 -- Fixed crash when combining Q() objects with boolean expressions.
Backport of00b0786de5from main. Regression in466920f6d7.
This commit is contained in:
		
				
					committed by
					
						 Mariusz Felisiak
						Mariusz Felisiak
					
				
			
			
				
	
			
			
			
						parent
						
							65dfb06a1a
						
					
				
				
					commit
					d0267690f8
				
			| @@ -112,14 +112,10 @@ class Q(tree.Node): | ||||
|         path = '%s.%s' % (self.__class__.__module__, self.__class__.__name__) | ||||
|         if path.startswith('django.db.models.query_utils'): | ||||
|             path = path.replace('django.db.models.query_utils', 'django.db.models') | ||||
|         args, kwargs = (), {} | ||||
|         if len(self.children) == 1 and not isinstance(self.children[0], Q): | ||||
|             child = self.children[0] | ||||
|             kwargs = {child[0]: child[1]} | ||||
|         else: | ||||
|         args = tuple(self.children) | ||||
|         kwargs = {} | ||||
|         if self.connector != self.default: | ||||
|                 kwargs = {'_connector': self.connector} | ||||
|             kwargs['_connector'] = self.connector | ||||
|         if self.negated: | ||||
|             kwargs['_negated'] = True | ||||
|         return path, args, kwargs | ||||
|   | ||||
| @@ -33,3 +33,6 @@ Bugfixes | ||||
|  | ||||
| * Fixed a bug in Django 3.2 where variable lookup errors were logged rendering | ||||
|   the sitemap template if alternates were not defined (:ticket:`32648`). | ||||
|  | ||||
| * Fixed a regression in Django 3.2 that caused a crash when combining ``Q()`` | ||||
|   objects which contains boolean expressions (:ticket:`32548`). | ||||
|   | ||||
| @@ -821,6 +821,10 @@ class BasicExpressionsTests(TestCase): | ||||
|             Q() & Exists(is_poc), | ||||
|             Exists(is_poc) | Q(), | ||||
|             Q() | Exists(is_poc), | ||||
|             Q(Exists(is_poc)) & Q(), | ||||
|             Q() & Q(Exists(is_poc)), | ||||
|             Q(Exists(is_poc)) | Q(), | ||||
|             Q() | Q(Exists(is_poc)), | ||||
|         ] | ||||
|         for conditions in tests: | ||||
|             with self.subTest(conditions): | ||||
|   | ||||
| @@ -1,6 +1,8 @@ | ||||
| from django.db.models import F, Q | ||||
| from django.db.models import Exists, F, OuterRef, Q | ||||
| from django.test import SimpleTestCase | ||||
|  | ||||
| from .models import Tag | ||||
|  | ||||
|  | ||||
| class QTests(SimpleTestCase): | ||||
|     def test_combine_and_empty(self): | ||||
| @@ -39,17 +41,14 @@ class QTests(SimpleTestCase): | ||||
|         q = Q(price__gt=F('discounted_price')) | ||||
|         path, args, kwargs = q.deconstruct() | ||||
|         self.assertEqual(path, 'django.db.models.Q') | ||||
|         self.assertEqual(args, ()) | ||||
|         self.assertEqual(kwargs, {'price__gt': F('discounted_price')}) | ||||
|         self.assertEqual(args, (('price__gt', F('discounted_price')),)) | ||||
|         self.assertEqual(kwargs, {}) | ||||
|  | ||||
|     def test_deconstruct_negated(self): | ||||
|         q = ~Q(price__gt=F('discounted_price')) | ||||
|         path, args, kwargs = q.deconstruct() | ||||
|         self.assertEqual(args, ()) | ||||
|         self.assertEqual(kwargs, { | ||||
|             'price__gt': F('discounted_price'), | ||||
|             '_negated': True, | ||||
|         }) | ||||
|         self.assertEqual(args, (('price__gt', F('discounted_price')),)) | ||||
|         self.assertEqual(kwargs, {'_negated': True}) | ||||
|  | ||||
|     def test_deconstruct_or(self): | ||||
|         q1 = Q(price__gt=F('discounted_price')) | ||||
| @@ -88,6 +87,13 @@ class QTests(SimpleTestCase): | ||||
|         self.assertEqual(args, (Q(price__gt=F('discounted_price')),)) | ||||
|         self.assertEqual(kwargs, {}) | ||||
|  | ||||
|     def test_deconstruct_boolean_expression(self): | ||||
|         tagged = Tag.objects.filter(category=OuterRef('pk')) | ||||
|         q = Q(Exists(tagged)) | ||||
|         _, args, kwargs = q.deconstruct() | ||||
|         self.assertEqual(args, (Exists(tagged),)) | ||||
|         self.assertEqual(kwargs, {}) | ||||
|  | ||||
|     def test_reconstruct(self): | ||||
|         q = Q(price__gt=F('discounted_price')) | ||||
|         path, args, kwargs = q.deconstruct() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user