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 Simon Charette, 4 years ago

Easy pickings: set
Triage Stage: UnreviewedAccepted

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.

Version 0, edited 4 years ago by Simon Charette (next)

comment:2 by Simon Charette, 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:  
    204204    def query(self):
    205205        if self._deferred_filter:
    206206            negate, args, kwargs = self._deferred_filter
    207             self._filter_or_exclude_inplace(negate, *args, **kwargs)
     207            self._filter_or_exclude_inplace(negate, args, kwargs)
    208208            self._deferred_filter = None
    209209        return self._query
    210210
    class QuerySet:  
    939939        set.
    940940        """
    941941        self._not_support_combined_queries('filter')
    942         return self._filter_or_exclude(False, *args, **kwargs)
     942        return self._filter_or_exclude(False, args, kwargs)
    943943
    944944    def exclude(self, *args, **kwargs):
    945945        """
    class QuerySet:  
    947947        set.
    948948        """
    949949        self._not_support_combined_queries('exclude')
    950         return self._filter_or_exclude(True, *args, **kwargs)
     950        return self._filter_or_exclude(True, args, kwargs)
    951951
    952     def _filter_or_exclude(self, negate, *args, **kwargs):
     952    def _filter_or_exclude(self, negate, args, kwargs):
    953953        if args or kwargs:
    954954            assert not self.query.is_sliced, \
    955955                "Cannot filter a query once a slice has been taken."
    class QuerySet:  
    959959            self._defer_next_filter = False
    960960            clone._deferred_filter = negate, args, kwargs
    961961        else:
    962             clone._filter_or_exclude_inplace(negate, *args, **kwargs)
     962            clone._filter_or_exclude_inplace(negate, args, kwargs)
    963963        return clone
    964964
    965     def _filter_or_exclude_inplace(self, negate, *args, **kwargs):
     965    def _filter_or_exclude_inplace(self, negate, args, kwargs):
    966966        if negate:
    967967            self._query.add_q(~Q(*args, **kwargs))
    968968        else:
    class QuerySet:  
    983983            clone.query.add_q(filter_obj)
    984984            return clone
    985985        else:
    986             return self._filter_or_exclude(False, **filter_obj)
     986            return self._filter_or_exclude(False, args=(), kwargs=filter_obj)
    987987
    988988    def _combinator_query(self, combinator, *other_qs, all=False):
    989989        # Clone the query to inherit the select list and everything

in reply to:  2 comment:3 by Aaron Kirkbride, 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 :)

Last edited 4 years ago by Aaron Kirkbride (previous) (diff)

comment:4 by Aaron Kirkbride, 4 years ago

Owner: changed from nobody to Aaron Kirkbride
Status: newassigned

comment:5 by Hasan Ramezani, 4 years ago

Has patch: set
Owner: changed from Aaron Kirkbride to Hasan Ramezani
Last edited 4 years ago by Mariusz Felisiak (previous) (diff)

in reply to:  5 comment:6 by Aaron Kirkbride, 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 Simon Charette, 4 years ago

Triage Stage: AcceptedReady for checkin

comment:8 by Mariusz Felisiak <felisiak.mariusz@…>, 4 years ago

Resolution: fixed
Status: assignedclosed

In 9c9a3fe1:

Fixed #31783 -- Fixed crash when filtering againts "negate" field.

Thanks Simon Charette for the initial patch.

Note: See TracTickets for help on using tickets.
Back to Top