Ticket #9425: select-related-on-null.patch

File select-related-on-null.patch, 4.5 KB (added by Simon Law, 15 years ago)
  • django/db/models/query.py

    diff --git a/django/db/models/query.py b/django/db/models/query.py
    a b class QuerySet(object):  
    275275        for row in self.query.results_iter():
    276276            if fill_cache:
    277277                obj, _ = get_cached_row(self.model, row, index_start,
    278                         max_depth, requested=requested)
     278                                        max_depth, requested=requested,
     279                                        follow_null=self.query.follow_null)
    279280            else:
    280281                obj = self.model(*row[index_start:])
    281282            for i, k in enumerate(extra_select):
    class QuerySet(object):  
    532533        related objects are included in the selection.
    533534        """
    534535        depth = kwargs.pop('depth', 0)
     536        follow_null = kwargs.pop('follow_null', False)
    535537        if kwargs:
    536538            raise TypeError('Unexpected keyword arguments to select_related: %s'
    537539                    % (kwargs.keys(),))
    class QuerySet(object):  
    544546            obj.query.select_related = True
    545547        if depth:
    546548            obj.query.max_depth = depth
     549        obj.query.follow_null = follow_null
    547550        return obj
    548551
    549552    def dup_select_related(self, other):
    class EmptyQuerySet(QuerySet):  
    788791
    789792
    790793def get_cached_row(klass, row, index_start, max_depth=0, cur_depth=0,
    791                    requested=None):
     794                   requested=None, follow_null=False):
    792795    """
    793796    Helper function that recursively returns an object with the specified
    794797    related attributes already populated.
    def get_cached_row(klass, row, index_sta  
    806809    else:
    807810        obj = klass(*fields)
    808811    for f in klass._meta.fields:
    809         if not select_related_descend(f, restricted, requested):
     812        if not select_related_descend(f, restricted, requested, follow_null):
    810813            continue
    811814        if restricted:
    812815            next = requested[f.name]
    813816        else:
    814817            next = None
    815818        cached_row = get_cached_row(f.rel.to, row, index_end, max_depth,
    816                 cur_depth+1, next)
     819                cur_depth+1, next, follow_null)
    817820        if cached_row:
    818821            rel_obj, index_end = cached_row
    819822            if obj is not None:
  • django/db/models/query_utils.py

    diff --git a/django/db/models/query_utils.py b/django/db/models/query_utils.py
    a b class Q(tree.Node):  
    4848        obj.negate()
    4949        return obj
    5050
    51 def select_related_descend(field, restricted, requested):
     51def select_related_descend(field, restricted, requested, follow_null):
    5252    """
    5353    Returns True if this field should be used to descend deeper for
    5454    select_related() purposes. Used by both the query construction code
    def select_related_descend(field, restri  
    6161        return False
    6262    if restricted and field.name not in requested:
    6363        return False
    64     if not restricted and field.null:
     64    if not restricted and not follow_null and field.null:
    6565        return False
    6666    return True
    6767
  • django/db/models/sql/query.py

    diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
    a b class BaseQuery(object):  
    7777        # Arbitrary maximum limit for select_related. Prevents infinite
    7878        # recursion. Can be changed by the depth parameter to select_related().
    7979        self.max_depth = 5
     80
     81        # Does select_related follow fields that can be NULL?
     82        self.follow_null = False
    8083
    8184        # These are for extensions. The contents are more or less appended
    8285        # verbatim to the appropriate clause.
    class BaseQuery(object):  
    182185        obj.select_related = self.select_related
    183186        obj.related_select_cols = []
    184187        obj.max_depth = self.max_depth
     188        obj.follow_null = self.follow_null
    185189        obj.extra_select = self.extra_select.copy()
    186190        obj.extra_tables = self.extra_tables
    187191        obj.extra_where = self.extra_where
    class BaseQuery(object):  
    10141018                restricted = False
    10151019
    10161020        for f, model in opts.get_fields_with_model():
    1017             if not select_related_descend(f, restricted, requested):
     1021            if not select_related_descend(f, restricted, requested,
     1022                                          self.follow_null):
    10181023                continue
    10191024            # The "avoid" set is aliases we want to avoid just for this
    10201025            # particular branch of the recursion. They aren't permanently
Back to Top