mirror of
				https://github.com/django/django.git
				synced 2025-10-30 17:16:10 +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__) |         path = '%s.%s' % (self.__class__.__module__, self.__class__.__name__) | ||||||
|         if path.startswith('django.db.models.query_utils'): |         if path.startswith('django.db.models.query_utils'): | ||||||
|             path = path.replace('django.db.models.query_utils', 'django.db.models') |             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) |         args = tuple(self.children) | ||||||
|  |         kwargs = {} | ||||||
|         if self.connector != self.default: |         if self.connector != self.default: | ||||||
|                 kwargs = {'_connector': self.connector} |             kwargs['_connector'] = self.connector | ||||||
|         if self.negated: |         if self.negated: | ||||||
|             kwargs['_negated'] = True |             kwargs['_negated'] = True | ||||||
|         return path, args, kwargs |         return path, args, kwargs | ||||||
|   | |||||||
| @@ -33,3 +33,6 @@ Bugfixes | |||||||
|  |  | ||||||
| * Fixed a bug in Django 3.2 where variable lookup errors were logged rendering | * Fixed a bug in Django 3.2 where variable lookup errors were logged rendering | ||||||
|   the sitemap template if alternates were not defined (:ticket:`32648`). |   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), |             Q() & Exists(is_poc), | ||||||
|             Exists(is_poc) | Q(), |             Exists(is_poc) | Q(), | ||||||
|             Q() | Exists(is_poc), |             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: |         for conditions in tests: | ||||||
|             with self.subTest(conditions): |             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 django.test import SimpleTestCase | ||||||
|  |  | ||||||
|  | from .models import Tag | ||||||
|  |  | ||||||
|  |  | ||||||
| class QTests(SimpleTestCase): | class QTests(SimpleTestCase): | ||||||
|     def test_combine_and_empty(self): |     def test_combine_and_empty(self): | ||||||
| @@ -39,17 +41,14 @@ class QTests(SimpleTestCase): | |||||||
|         q = Q(price__gt=F('discounted_price')) |         q = Q(price__gt=F('discounted_price')) | ||||||
|         path, args, kwargs = q.deconstruct() |         path, args, kwargs = q.deconstruct() | ||||||
|         self.assertEqual(path, 'django.db.models.Q') |         self.assertEqual(path, 'django.db.models.Q') | ||||||
|         self.assertEqual(args, ()) |         self.assertEqual(args, (('price__gt', F('discounted_price')),)) | ||||||
|         self.assertEqual(kwargs, {'price__gt': F('discounted_price')}) |         self.assertEqual(kwargs, {}) | ||||||
|  |  | ||||||
|     def test_deconstruct_negated(self): |     def test_deconstruct_negated(self): | ||||||
|         q = ~Q(price__gt=F('discounted_price')) |         q = ~Q(price__gt=F('discounted_price')) | ||||||
|         path, args, kwargs = q.deconstruct() |         path, args, kwargs = q.deconstruct() | ||||||
|         self.assertEqual(args, ()) |         self.assertEqual(args, (('price__gt', F('discounted_price')),)) | ||||||
|         self.assertEqual(kwargs, { |         self.assertEqual(kwargs, {'_negated': True}) | ||||||
|             'price__gt': F('discounted_price'), |  | ||||||
|             '_negated': True, |  | ||||||
|         }) |  | ||||||
|  |  | ||||||
|     def test_deconstruct_or(self): |     def test_deconstruct_or(self): | ||||||
|         q1 = Q(price__gt=F('discounted_price')) |         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(args, (Q(price__gt=F('discounted_price')),)) | ||||||
|         self.assertEqual(kwargs, {}) |         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): |     def test_reconstruct(self): | ||||||
|         q = Q(price__gt=F('discounted_price')) |         q = Q(price__gt=F('discounted_price')) | ||||||
|         path, args, kwargs = q.deconstruct() |         path, args, kwargs = q.deconstruct() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user