Changeset 6899
- Timestamp:
- 12/09/07 00:24:17 (7 months ago)
- Files:
-
- django/branches/queryset-refactor/django/db/models/query.py (modified) (5 diffs)
- django/branches/queryset-refactor/django/db/models/sql/query.py (modified) (4 diffs)
- django/branches/queryset-refactor/docs/db-api.txt (modified) (2 diffs)
- django/branches/queryset-refactor/tests/modeltests/select_related/models.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/queryset-refactor/django/db/models/query.py
r6857 r6899 86 86 """ 87 87 fill_cache = self.query.select_related 88 if isinstance(fill_cache, dict): 89 requested = fill_cache 90 else: 91 requested = None 88 92 max_depth = self.query.max_depth 89 93 index_end = len(self.model._meta.fields) … … 91 95 for row in self.query.results_iter(): 92 96 if fill_cache: 93 obj, index_end = get_cached_row( klass=self.model, row=row,94 index_start=0, max_depth=max_depth)97 obj, index_end = get_cached_row(self.model, row, 0, max_depth, 98 requested=requested) 95 99 else: 96 100 obj = self.model(*row[:index_end]) … … 299 303 return self._filter_or_exclude(None, **filter_obj) 300 304 301 def select_related(self, true_or_false=True, depth=0): 302 """Returns a new QuerySet instance that will select related objects.""" 305 def select_related(self, *fields, **kwargs): 306 """ 307 Returns a new QuerySet instance that will select related objects. If 308 fields are specified, they must be ForeignKey fields and only those 309 related objects are included in the selection. 310 """ 311 depth = kwargs.pop('depth', 0) 312 # TODO: Remove this? select_related(False) isn't really useful. 313 true_or_false = kwargs.pop('true_or_false', True) 314 if kwargs: 315 raise TypeError('Unexpected keyword arguments to select_related: %s' 316 % (kwargs.keys(),)) 303 317 obj = self._clone() 304 obj.query.select_related = true_or_false 318 if fields: 319 if depth: 320 raise TypeError('Cannot pass both "depth" and fields to select_related()') 321 obj.query.add_select_related(fields) 322 else: 323 obj.query.select_related = true_or_false 305 324 if depth: 306 325 obj.query.max_depth = depth … … 371 390 def __init__(self, *args, **kwargs): 372 391 super(ValuesQuerySet, self).__init__(*args, **kwargs) 373 # select_related isn't supported in values(). 392 # select_related isn't supported in values(). (FIXME -#3358) 374 393 self.query.select_related = False 375 394 … … 491 510 QOr = QAnd = QOperator 492 511 493 def get_cached_row(klass, row, index_start, max_depth=0, cur_depth=0): 512 def get_cached_row(klass, row, index_start, max_depth=0, cur_depth=0, 513 requested=None): 494 514 """Helper function that recursively returns an object with cache filled""" 495 515 496 # If we've got a max_depth set and we've exceeded that depth, bail now.497 if max_depth and cur_depth > max_depth:516 if max_depth and requested is None and cur_depth > max_depth: 517 # We've recursed deeply enough; stop now. 498 518 return None 499 519 520 restricted = requested is not None 500 521 index_end = index_start + len(klass._meta.fields) 501 522 obj = klass(*row[index_start:index_end]) 502 523 for f in klass._meta.fields: 503 if f.rel and not f.null: 504 cached_row = get_cached_row(f.rel.to, row, index_end, max_depth, cur_depth+1) 524 if f.rel and ((not restricted and not f.null) or 525 (restricted and f.name in requested)): 526 if restricted: 527 next = requested[f.name] 528 else: 529 next = None 530 cached_row = get_cached_row(f.rel.to, row, index_end, max_depth, 531 cur_depth+1, next) 505 532 if cached_row: 506 533 rel_obj, index_end = cached_row django/branches/queryset-refactor/django/db/models/sql/query.py
r6869 r6899 637 637 638 638 def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1, 639 used=None ):639 used=None, requested=None, restricted=None): 640 640 """ 641 641 Fill in the information needed for a select_related query. The current 642 "depth" is measured as the number of connections away from the root643 model (cur_depth ==1 means we are looking at models with direct642 depth is measured as the number of connections away from the root model 643 (for example, cur_depth=1 means we are looking at models with direct 644 644 connections to the root model). 645 645 """ 646 if self.max_depth and cur_depth > self.max_depth:647 # We've recursed too deeply; bail out.646 if not restricted and self.max_depth and cur_depth > self.max_depth: 647 # We've recursed far enough; bail out. 648 648 return 649 649 if not opts: … … 654 654 used = [] 655 655 656 # Setup for the case when only particular related fields should be 657 # included in the related selection. 658 if requested is None and restricted is not False: 659 if isinstance(self.select_related, dict): 660 requested = self.select_related 661 restricted = True 662 else: 663 restricted = False 664 656 665 for f in opts.fields: 657 if not f.rel or f.null: 666 if (not f.rel or (restricted and f.name not in requested) or 667 (not restricted and f.null)): 658 668 continue 659 669 table = f.rel.to._meta.db_table … … 663 673 self.select.extend([(alias, f2.column) 664 674 for f2 in f.rel.to._meta.fields]) 675 if restricted: 676 next = requested.get(f.name, {}) 677 else: 678 next = False 665 679 self.fill_related_selections(f.rel.to._meta, alias, cur_depth + 1, 666 used )680 used, next, restricted) 667 681 668 682 def add_filter(self, filter_expr, connector=AND, negate=False): … … 1007 1021 self.extra_select = SortedDict() 1008 1022 1023 def add_select_related(self, fields): 1024 """ 1025 Sets up the select_related data structure so that we only select 1026 certain related models (as opposed to all models, when 1027 self.select_related=True). 1028 """ 1029 field_dict = {} 1030 for field in fields: 1031 d = field_dict 1032 for part in field.split(LOOKUP_SEP): 1033 d = d.setdefault(part, {}) 1034 self.select_related = field_dict 1035 1009 1036 def execute_sql(self, result_type=MULTI): 1010 1037 """ django/branches/queryset-refactor/docs/db-api.txt
r6760 r6899 745 745 c = p.hometown # Hits the database. 746 746 747 Note that ``select_related()`` does not follow foreign keys that have748 ``null=True``.747 Note that, by default, ``select_related()`` does not follow foreign keys that 748 have ``null=True``. 749 749 750 750 Usually, using ``select_related()`` can vastly improve performance because your … … 762 762 763 763 The ``depth`` argument is new in the Django development version. 764 765 **New in Django development version:** Sometimes you only need to access 766 specific models that are related to your root model, not all of the related 767 models. In these cases, you can pass the related field names to 768 ``select_related()`` and it will only follow those relations. You can even do 769 this for models that are more than one relation away by separating the field 770 names with double underscores, just as for filters. For example, if we have 771 thise model:: 772 773 class Room(models.Model): 774 # ... 775 building = models.ForeignKey(...) 776 777 class Group(models.Model): 778 # ... 779 teacher = models.ForeignKey(...) 780 room = models.ForeignKey(Room) 781 subject = models.ForeignKey(...) 782 783 ...and we only needed to work with the ``room`` and ``subject`` attributes, we 784 could write this:: 785 786 g = Group.objects.select_related('room', 'subject') 787 788 This is also valid:: 789 790 g = Group.objects.select_related('room__building', 'subject') 791 792 ...and would also pull in the ``building`` relation. 793 794 You can only refer to ``ForeignKey`` relations in the list of fields passed to 795 ``select_related``. You *can* refer to foreign keys that have ``null=True`` 796 (unlike the default ``select_related()`` call). It's an error to use both a 797 list of fields and the ``depth`` parameter in the same ``select_related()`` 798 call, since they are conflicting options. 764 799 765 800 ``extra(select=None, where=None, params=None, tables=None, order_by=None)`` django/branches/queryset-refactor/tests/modeltests/select_related/models.py
r6857 r6899 130 130 <Domain: Eukaryota> 131 131 132 # Notice: one few querythan above because of depth=1132 # Notice: one fewer queries than above because of depth=1 133 133 >>> len(db.connection.queries) 134 134 7 … … 152 152 True 153 153 154 # Reset DEBUG to where we found it. 154 # The optional fields passed to select_related() control which related models 155 # we pull in. This allows for smaller queries and can act as an alternative 156 # (or, in addition to) the depth parameter. 157 158 # In the next two cases, we explicitly say to select the 'genus' and 159 # 'genus.family' models, leading to the same number of queries as before. 160 >>> db.reset_queries() 161 >>> world = Species.objects.select_related('genus__family') 162 >>> [o.genus.family for o in world] 163 [<Family: Drosophilidae>, <Family: Hominidae>, <Family: Fabaceae>, <Family: Amanitacae>] 164 >>> len(db.connection.queries) 165 1 166 167 >>> db.reset_queries() 168 >>> world = Species.objects.filter(genus__name='Amanita').select_related('genus__family') 169 >>> [o.genus.family.order for o in world] 170 [<Order: Agaricales>] 171 >>> len(db.connection.queries) 172 2 173 174 >>> db.reset_queries() 175 >>> Species.objects.all().select_related('genus__family__order').order_by('id')[0:1].get().genus.family.order.name 176 u'Diptera' 177 >>> len(db.connection.queries) 178 1 179 180 # Specifying both "depth" and fields is an error. 181 >>> Species.objects.select_related('genus__family__order', depth=4) 182 Traceback (most recent call last): 183 ... 184 TypeError: Cannot pass both "depth" and fields to select_related() 185 186 # Reser DEBUG to where we found it. 155 187 >>> settings.DEBUG = False 156 188 """}
