Opened 4 years ago
Closed 4 years ago
#31783 closed Bug (fixed)
Filtering on a field named `negate` raises a TypeError
Reported by: | Aaron Kirkbride | Owned by: | Hasan Ramezani |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 3.0 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Ready for checkin | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | yes | UI/UX: | no |
Description
Filtering on a model with a field named negate
raises a TypeError
.
For example:
class Foo(models.Model): negate = models.BooleanField() Foo.objects.filter(negate=True)
raises TypeError: _filter_or_exclude() got multiple values for argument 'negate'
negate
is not documented as a reserved argument for .filter()
. I'm currently using .filter(negate__exact=True)
as a workaround.
Change History (8)
comment:1 by , 4 years ago
Easy pickings: | set |
---|---|
Triage Stage: | Unreviewed → Accepted |
follow-up: 3 comment:2 by , 4 years ago
Aaron, would you be interested in submitting a PR with the changes below plus a regression test in tests/query/tests.py
?
-
django/db/models/query.py
diff --git a/django/db/models/query.py b/django/db/models/query.py index 07d6ffd4ca..d655ede8d9 100644
a b class QuerySet: 204 204 def query(self): 205 205 if self._deferred_filter: 206 206 negate, args, kwargs = self._deferred_filter 207 self._filter_or_exclude_inplace(negate, *args, **kwargs)207 self._filter_or_exclude_inplace(negate, args, kwargs) 208 208 self._deferred_filter = None 209 209 return self._query 210 210 … … class QuerySet: 939 939 set. 940 940 """ 941 941 self._not_support_combined_queries('filter') 942 return self._filter_or_exclude(False, *args, **kwargs)942 return self._filter_or_exclude(False, args, kwargs) 943 943 944 944 def exclude(self, *args, **kwargs): 945 945 """ … … class QuerySet: 947 947 set. 948 948 """ 949 949 self._not_support_combined_queries('exclude') 950 return self._filter_or_exclude(True, *args, **kwargs)950 return self._filter_or_exclude(True, args, kwargs) 951 951 952 def _filter_or_exclude(self, negate, *args, **kwargs):952 def _filter_or_exclude(self, negate, args, kwargs): 953 953 if args or kwargs: 954 954 assert not self.query.is_sliced, \ 955 955 "Cannot filter a query once a slice has been taken." … … class QuerySet: 959 959 self._defer_next_filter = False 960 960 clone._deferred_filter = negate, args, kwargs 961 961 else: 962 clone._filter_or_exclude_inplace(negate, *args, **kwargs)962 clone._filter_or_exclude_inplace(negate, args, kwargs) 963 963 return clone 964 964 965 def _filter_or_exclude_inplace(self, negate, *args, **kwargs):965 def _filter_or_exclude_inplace(self, negate, args, kwargs): 966 966 if negate: 967 967 self._query.add_q(~Q(*args, **kwargs)) 968 968 else: … … class QuerySet: 983 983 clone.query.add_q(filter_obj) 984 984 return clone 985 985 else: 986 return self._filter_or_exclude(False, **filter_obj)986 return self._filter_or_exclude(False, args=(), kwargs=filter_obj) 987 987 988 988 def _combinator_query(self, combinator, *other_qs, all=False): 989 989 # Clone the query to inherit the select list and everything
comment:3 by , 4 years ago
Replying to Simon Charette:
Aaron, would you be interested in submitting a PR with the changes below plus a regression test in
tests/query/tests.py
?
Sure! I can do that this evening. Thanks for the patch :)
comment:4 by , 4 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
follow-up: 6 comment:5 by , 4 years ago
Has patch: | set |
---|---|
Owner: | changed from | to
comment:6 by , 4 years ago
Replying to Hasan Ramezani:
Thanks Hasan for creating the PR :) Sorry I didn't get round to this earlier.
comment:7 by , 4 years ago
Triage Stage: | Accepted → Ready for checkin |
---|
We should either document this limitation or change
_filter_or_exclude
and friends signature from(negate, *args, **kwargs)
to(negate, args, kwargs)
.I think the second approach is favourable as there's not much benefits in using arguments unpacking in these private methods.