Django

Code

Ticket #3592: ticket-3592-joins.diff

File ticket-3592-joins.diff, 3.5 kB (added by mir@noris.de, 1 year ago)

Improved patch, replaces the older one

  • a/django/db/models/query.py

    old new  
    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: 
     
    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 
     
    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"