Django

Code

Changeset 2997

Show
Ignore:
Timestamp:
05/26/06 18:41:43 (3 years ago)
Author:
lukeplant
Message:

Fixed bug with QuerySet?.exclude() failing to do negations on Q objects, and
at the same time generalised exclude/QNot so that they work for 'external'
Q objects i.e. ones that simply have 'get_sql' defined.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/db/models/query.py

    r2992 r2997  
    292292    def filter(self, *args, **kwargs): 
    293293        "Returns a new QuerySet instance with the args ANDed to the existing set." 
    294         return self._filter_or_exclude(Q, *args, **kwargs) 
     294        return self._filter_or_exclude(None, *args, **kwargs) 
    295295 
    296296    def exclude(self, *args, **kwargs): 
     
    298298        return self._filter_or_exclude(QNot, *args, **kwargs) 
    299299 
    300     def _filter_or_exclude(self, qtype, *args, **kwargs): 
     300    def _filter_or_exclude(self, mapper, *args, **kwargs): 
     301        # mapper is a callable used to transform Q objects, 
     302        # or None for identity transform 
     303        if mapper is None: 
     304            mapper = lambda x: x 
    301305        if len(args) > 0 or len(kwargs) > 0: 
    302306            assert self._limit is None and self._offset is None, \ 
     
    305309        clone = self._clone() 
    306310        if len(kwargs) > 0: 
    307             clone._filters = clone._filters & qtype(**kwargs
     311            clone._filters = clone._filters & mapper(Q(**kwargs)
    308312        if len(args) > 0: 
    309             clone._filters = clone._filters & reduce(operator.and_, args
     313            clone._filters = clone._filters & reduce(operator.and_, map(mapper, args)
    310314        return clone 
    311315 
     
    319323            return self._filter_or_exclude(None, filter_obj) 
    320324        else: 
    321             return self._filter_or_exclude(Q, **filter_obj) 
     325            return self._filter_or_exclude(None, **filter_obj) 
    322326 
    323327    def select_related(self, true_or_false=True): 
     
    583587class QNot(Q): 
    584588    "Encapsulates NOT (...) queries as objects" 
     589    def __init__(self, q): 
     590        "Creates a negation of the q object passed in." 
     591        self.q = q 
    585592 
    586593    def get_sql(self, opts): 
    587         tables, joins, where, params = super(QNot, self).get_sql(opts) 
     594        tables, joins, where, params = self.q.get_sql(opts) 
    588595        where2 = ['(NOT (%s))' % " AND ".join(where)] 
    589596        return tables, joins, where2, params 
  • django/trunk/tests/modeltests/or_lookups/models.py

    r2897 r2997  
    9090{1: Hello} 
    9191 
     92# Demonstrating exclude with a Q object 
     93>>> Article.objects.exclude(Q(headline__startswith='Hello')) 
     94[Goodbye] 
     95 
    9296# The 'complex_filter' method supports framework features such as  
    9397# 'limit_choices_to' which normally take a single dictionary of lookup arguments