Fixed #31783 -- Fixed crash when filtering againts "negate" field.
Thanks Simon Charette for the initial patch.
This commit is contained in:
parent
b6dfdaff33
commit
9c9a3fe118
|
@ -204,7 +204,7 @@ class QuerySet:
|
||||||
def query(self):
|
def query(self):
|
||||||
if self._deferred_filter:
|
if self._deferred_filter:
|
||||||
negate, args, kwargs = self._deferred_filter
|
negate, args, kwargs = self._deferred_filter
|
||||||
self._filter_or_exclude_inplace(negate, *args, **kwargs)
|
self._filter_or_exclude_inplace(negate, args, kwargs)
|
||||||
self._deferred_filter = None
|
self._deferred_filter = None
|
||||||
return self._query
|
return self._query
|
||||||
|
|
||||||
|
@ -939,7 +939,7 @@ class QuerySet:
|
||||||
set.
|
set.
|
||||||
"""
|
"""
|
||||||
self._not_support_combined_queries('filter')
|
self._not_support_combined_queries('filter')
|
||||||
return self._filter_or_exclude(False, *args, **kwargs)
|
return self._filter_or_exclude(False, args, kwargs)
|
||||||
|
|
||||||
def exclude(self, *args, **kwargs):
|
def exclude(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -947,9 +947,9 @@ class QuerySet:
|
||||||
set.
|
set.
|
||||||
"""
|
"""
|
||||||
self._not_support_combined_queries('exclude')
|
self._not_support_combined_queries('exclude')
|
||||||
return self._filter_or_exclude(True, *args, **kwargs)
|
return self._filter_or_exclude(True, args, kwargs)
|
||||||
|
|
||||||
def _filter_or_exclude(self, negate, *args, **kwargs):
|
def _filter_or_exclude(self, negate, args, kwargs):
|
||||||
if args or kwargs:
|
if args or kwargs:
|
||||||
assert not self.query.is_sliced, \
|
assert not self.query.is_sliced, \
|
||||||
"Cannot filter a query once a slice has been taken."
|
"Cannot filter a query once a slice has been taken."
|
||||||
|
@ -959,10 +959,10 @@ class QuerySet:
|
||||||
self._defer_next_filter = False
|
self._defer_next_filter = False
|
||||||
clone._deferred_filter = negate, args, kwargs
|
clone._deferred_filter = negate, args, kwargs
|
||||||
else:
|
else:
|
||||||
clone._filter_or_exclude_inplace(negate, *args, **kwargs)
|
clone._filter_or_exclude_inplace(negate, args, kwargs)
|
||||||
return clone
|
return clone
|
||||||
|
|
||||||
def _filter_or_exclude_inplace(self, negate, *args, **kwargs):
|
def _filter_or_exclude_inplace(self, negate, args, kwargs):
|
||||||
if negate:
|
if negate:
|
||||||
self._query.add_q(~Q(*args, **kwargs))
|
self._query.add_q(~Q(*args, **kwargs))
|
||||||
else:
|
else:
|
||||||
|
@ -983,7 +983,7 @@ class QuerySet:
|
||||||
clone.query.add_q(filter_obj)
|
clone.query.add_q(filter_obj)
|
||||||
return clone
|
return clone
|
||||||
else:
|
else:
|
||||||
return self._filter_or_exclude(False, **filter_obj)
|
return self._filter_or_exclude(False, args=(), kwargs=filter_obj)
|
||||||
|
|
||||||
def _combinator_query(self, combinator, *other_qs, all=False):
|
def _combinator_query(self, combinator, *other_qs, all=False):
|
||||||
# Clone the query to inherit the select list and everything
|
# Clone the query to inherit the select list and everything
|
||||||
|
|
|
@ -42,6 +42,7 @@ class Note(models.Model):
|
||||||
note = models.CharField(max_length=100)
|
note = models.CharField(max_length=100)
|
||||||
misc = models.CharField(max_length=10)
|
misc = models.CharField(max_length=10)
|
||||||
tag = models.ForeignKey(Tag, models.SET_NULL, blank=True, null=True)
|
tag = models.ForeignKey(Tag, models.SET_NULL, blank=True, null=True)
|
||||||
|
negate = models.BooleanField(default=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['note']
|
ordering = ['note']
|
||||||
|
|
|
@ -47,7 +47,7 @@ class Queries1Tests(TestCase):
|
||||||
|
|
||||||
cls.n1 = Note.objects.create(note='n1', misc='foo', id=1)
|
cls.n1 = Note.objects.create(note='n1', misc='foo', id=1)
|
||||||
cls.n2 = Note.objects.create(note='n2', misc='bar', id=2)
|
cls.n2 = Note.objects.create(note='n2', misc='bar', id=2)
|
||||||
cls.n3 = Note.objects.create(note='n3', misc='foo', id=3)
|
cls.n3 = Note.objects.create(note='n3', misc='foo', id=3, negate=False)
|
||||||
|
|
||||||
ann1 = Annotation.objects.create(name='a1', tag=cls.t1)
|
ann1 = Annotation.objects.create(name='a1', tag=cls.t1)
|
||||||
ann1.notes.add(cls.n1)
|
ann1.notes.add(cls.n1)
|
||||||
|
@ -1216,6 +1216,13 @@ class Queries1Tests(TestCase):
|
||||||
[self.a3, self.a4],
|
[self.a3, self.a4],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_negate_field(self):
|
||||||
|
self.assertSequenceEqual(
|
||||||
|
Note.objects.filter(negate=True),
|
||||||
|
[self.n1, self.n2],
|
||||||
|
)
|
||||||
|
self.assertSequenceEqual(Note.objects.exclude(negate=True), [self.n3])
|
||||||
|
|
||||||
|
|
||||||
class Queries2Tests(TestCase):
|
class Queries2Tests(TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
Loading…
Reference in New Issue