Ticket #3592: ticket-3592-joins.diff

File ticket-3592-joins.diff, 3.5 KB (added by mir@…, 17 years ago)

Improved patch, replaces the older one

  • django/db/models/query.py

    From nobody Mon Sep 17 00:00:00 2001
    From: Michael Radziej <mir@noris.de>
    Date: Fri Mar 9 20:32:31 2007 +0100
    Subject: [PATCH] outer for or
    
    Refreshed patch outer-for-or.
    (Base: f59ca82d7e4a6d495bda443b56b49a2e00678cc0)
    (Last: 500c179ee84b8984680d7e7a3b21adec7cd8fb51)
    
    ---
    
     django/db/models/query.py |   69 ++++++++++++++++++++++++++++++++++++++++++++-
     1 files changed, 68 insertions(+), 1 deletions(-)
    
    base c2e6175cdf58493d0c1325be40d41a33c8105919
    last 8118dc0da5a118e665f725529c4a8ed3a665e247
    diff --git a/django/db/models/query.py b/django/db/models/query.py
    index c6f1c1d6b1d35127aedcb1f19f70a635ad0a651c..864783a87223896de0d38bd88748bdd87b16639d 100644
    a b class EmptyQuerySet(QuerySet):  
    703703
    704704class QOperator(object):
    705705    "Base class for QAnd and QOr"
     706    underneath_an_or = False # used to track ORs
     707    checked_or       = False
     708   
     709    def search_for_or(self):
     710        " Returns true if an or exists beneath this Q operator. "
     711        if type(self) == QOr:
     712            return True
     713
     714        for val in self.args:
     715            if val.search_for_or():
     716                return True
     717
     718        return False # there was no OR below this.
     719
     720    def set_or_found(self, or_value):
     721        if self.checked_or:
     722            return
     723
     724        self.underneath_an_or = or_value
     725        self.checked_or       = True
     726
     727        for val in self.args:
     728            val.set_or_found(or_value) # set for all the children
     729       
    706730    def __init__(self, *args):
    707731        self.args = args
    708732
    709733    def get_sql(self, opts):
     734
     735        if not self.checked_or:
     736            found_an_or = self.search_for_or()
     737            self.set_or_found(found_an_or)
     738
     739        # now that we've finished building the query
     740        self.checked_or = False
     741
    710742        joins, where, params = SortedDict(), [], []
    711743        for val in self.args:
    712744            try:
    class QOr(QOperator):  
    751783
    752784class Q(object):
    753785    "Encapsulates queries as objects that can be combined logically."
     786    underneath_an_or = False
     787    checked_or       = False
     788    outer_join       = 'LEFT OUTER JOIN'
     789    inner_join       = 'INNER JOIN'
     790   
    754791    def __init__(self, **kwargs):
    755792        self.kwargs = kwargs
    756793
    class Q(object):  
    760797    def __or__(self, other):
    761798        return QOr(self, other)
    762799
     800    def search_for_or(self):
     801        ' Returns false, since there are no OR Qs below. '
     802        return False
     803
     804    def set_or_found(self, or_found):
     805        """ Set whether or not we have an OR above us. """
     806        if not self.checked_or:
     807            self.underneath_an_or = or_found
     808            self.checked_or       = True  # we checked for an OR
     809
    763810    def get_sql(self, opts):
    764         return parse_lookup(self.kwargs.items(), opts)
     811        # we will check to see if it's an OR, and change the join
     812        # based upon that
     813
     814        if self.underneath_an_or:
     815            join_text = self.outer_join
     816        else:
     817            join_text = self.inner_join
     818
     819        joins, where, params = parse_lookup(self.kwargs.items(), opts)
     820
     821        joins2 = {}
     822        for item, key in joins.items():
     823            # now we will fix the joins dictionary with
     824            # the new type of join
     825            joins2[item] = (key[0], join_text, key[2])
     826
     827        # now that we've done creating the query,
     828        # it's best that we let ourselves search again
     829        self.checked_or = False
     830
     831        return joins2, where, params
    765832
    766833class QNot(Q):
    767834    "Encapsulates NOT (...) queries as objects"
Back to Top