Ticket #5020: query.py.diff

File query.py.diff, 5.4 KB (added by David Cramer <dcramer@…>, 12 years ago)
  • django/trunk/django/db/models/query.py

     
    408408        else:
    409409            return self._filter_or_exclude(None, **filter_obj)
    410410
    411     def select_related(self, true_or_false=True, depth=0):
     411    def select_related(self, *args, **kwargs):
    412412        "Returns a new QuerySet instance with '_select_related' modified."
    413         return self._clone(_select_related=true_or_false, _max_related_depth=depth)
     413        true_or_false = kwargs.pop('true_or_false', True)
     414        depth = kwargs.pop('depth', 0)
     415        return self._clone(_select_related=true_or_false, _max_related_depth=depth, _recurse_fields=fields)
    414416
    415417    def order_by(self, *field_names):
    416418        "Returns a new QuerySet instance with the ordering changed."
     
    819821            raise NotImplementedError
    820822    raise TypeError, "Got invalid lookup_type: %s" % repr(lookup_type)
    821823
    822 def get_cached_row(klass, row, index_start, max_depth=0, cur_depth=0):
     824def get_cached_row(klass, row, index_start, fields=None, max_depth=0, cur_depth=0):
    823825    """Helper function that recursively returns an object with cache filled"""
    824826
    825827    # If we've got a max_depth set and we've exceeded that depth, bail now.
    826     if max_depth and cur_depth > max_depth:
     828    if max_depth and cur_depth >= max_depth:
    827829        return None
    828830
     831    fields_to_join = get_select_related_fields(klass._meta, fields)
     832
    829833    index_end = index_start + len(klass._meta.fields)
    830834    obj = klass(*row[index_start:index_end])
    831     for f in klass._meta.fields:
    832         if f.rel and not f.null:
    833             cached_row = get_cached_row(f.rel.to, row, index_end, max_depth, cur_depth+1)
    834             if cached_row:
    835                 rel_obj, index_end = cached_row
    836                 setattr(obj, f.get_cache_name(), rel_obj)
     835    for f in fields_to_join.iterkeys():
     836       cached_row = get_cached_row(f.rel.to, row, index_end, fields_to_join[f], max_depth, cur_depth+1)
     837       if cached_row:
     838               rel_obj, index_end = cached_row
     839               setattr(obj, f.get_cache_name(), rel_obj)
    837840    return obj, index_end
    838841
    839 def fill_table_cache(opts, select, tables, where, old_prefix, cache_tables_seen, max_depth=0, cur_depth=0):
     842def get_select_related_fields(opts, fields=None):
     843    """
     844    Helper function that returns a dictionary of fields for select_related()
     845    """
     846    if fields is None:
     847        fields_to_join = dict([(f, None) for f in opts.fields if f.rel and not f.null])
     848    else:
     849        fields_for_lookup = dict([(f.name, f) for f in opts.fields if f.rel])
     850        fields_to_join = dict()
     851        for f in fields:
     852            path = f.split(LOOKUP_SEPARATOR)
     853            try:
     854                fn = fields_for_lookup[path[0]]
     855                if fn not in fields_to_join:
     856                    fields_to_join[fn] = []
     857                if len(path) > 1:
     858                    fields_to_join[fn].append(LOOKUP_SEPARATOR.join(path[1:]))
     859            except KeyError:
     860                raise FieldDoesNotExist, '%s has no field named %s' % (opts.object_name, path[0])
     861    return fields_to_join
     862
     863def fill_table_cache(opts, select, tables, where, old_prefix, cache_tables_seen, max_depth=0, fields=None, cur_depth=0):
    840864    """
    841865    Helper function that recursively populates the select, tables and where (in
    842866    place) for select_related queries.
     867
     868    Implicit select_related calls on NULL fields will force an INNER JOIN currently.
    843869    """
    844870
    845871    # If we've got a max_depth set and we've exceeded that depth, bail now.
    846     if max_depth and cur_depth > max_depth:
     872    if max_depth and cur_depth >= max_depth:
    847873        return None
    848874
     875    fields_to_join = get_select_related_fields(opts, fields)
     876
    849877    qn = backend.quote_name
    850     for f in opts.fields:
    851         if f.rel and not f.null:
    852             db_table = f.rel.to._meta.db_table
    853             if db_table not in cache_tables_seen:
    854                 tables.append(qn(db_table))
    855             else: # The table was already seen, so give it a table alias.
    856                 new_prefix = '%s%s' % (db_table, len(cache_tables_seen))
    857                 tables.append('%s %s' % (qn(db_table), qn(new_prefix)))
    858                 db_table = new_prefix
    859             cache_tables_seen.append(db_table)
    860             where.append('%s.%s = %s.%s' % \
    861                 (qn(old_prefix), qn(f.column), qn(db_table), qn(f.rel.get_related_field().column)))
    862             select.extend(['%s.%s' % (qn(db_table), qn(f2.column)) for f2 in f.rel.to._meta.fields])
    863             fill_table_cache(f.rel.to._meta, select, tables, where, db_table, cache_tables_seen, max_depth, cur_depth+1)
     878    for f in fields_to_join.iterkeys():
     879        db_table = f.rel.to._meta.db_table
     880        if db_table not in cache_tables_seen:
     881            tables.append(qn(db_table))
     882        else: # The table was already seen, so give it a table alias.
     883            new_prefix = '%s%s' % (db_table, len(cache_tables_seen))
     884            tables.append('%s %s' % (qn(db_table), qn(new_prefix)))
     885            db_table = new_prefix
     886        cache_tables_seen.append(db_table)
     887        where.append('%s.%s = %s.%s' % \
     888            (qn(old_prefix), qn(f.column), qn(db_table), qn(f.rel.get_related_field().column)))
     889        select.extend(['%s.%s' % (qn(db_table), qn(f2.column)) for f2 in f.rel.to._meta.fields])
     890        fill_table_cache(f.rel.to._meta, select, tables, where, db_table, cache_tables_seen, max_depth, fields_to_join[f], cur_depth+1)
    864891
    865892def parse_lookup(kwarg_items, opts):
    866893    # Helper function that handles converting API kwargs
Back to Top