Ticket #2076: ticket-2076.3.diff
File ticket-2076.3.diff, 8.9 KB (added by , 18 years ago) |
---|
-
django/db/models/query.py
a b class QuerySet(object): 460 460 where.extend(where2) 461 461 params.extend(params2) 462 462 463 # Resolve order_by dependencies before joins to order by related tables 464 order_by = [] 465 if self._order_by is not None: # use order_by = () to disable ordering 466 ordering_to_use = self._order_by 467 else: 468 ordering_to_use = opts.ordering 469 470 for f in handle_legacy_orderlist(ordering_to_use): 471 if "." in f: # dot-style field, fall back to old ordering code below 472 order_by = [] 473 break 474 elif f == '?': # Special case. 475 order_by.append(backend.get_random_function_sql()) 476 break 477 elif f.startswith('-'): 478 path = f[1:].split(LOOKUP_SEPARATOR) 479 order = "DESC" 480 else: 481 path = f.split(LOOKUP_SEPARATOR) 482 order = "ASC" 483 484 joins3, where3, params3 = lookup_inner(path, 'exact', False, opts, opts.db_table, None) 485 joins.update(joins3) 486 487 # hack to get fieldname to order by. modify lookup_inner to supply this instead. 488 field = where3[0].replace(' = %s', '') 489 order_by.append('%s %s' % (field, order)) 490 463 491 # Add additional tables and WHERE clauses based on select_related. 464 492 if self._select_related: 465 493 fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table]) … … class QuerySet(object): 485 513 sql.append(where and "WHERE " + " AND ".join(where)) 486 514 487 515 # ORDER BY clause 488 order_by = []489 516 if self._order_by is not None: 490 517 ordering_to_use = self._order_by 491 518 else: 492 519 ordering_to_use = opts.ordering 520 if order_by: # dont try to set up ordering again if already done 521 ordering_to_use = [] 493 522 for f in handle_legacy_orderlist(ordering_to_use): 494 if f == '?': # Special case. 495 order_by.append(backend.get_random_function_sql()) 523 if f.startswith('-'): 524 col_name = f[1:] 525 order = "DESC" 496 526 else: 497 if f.startswith('-'): 498 col_name = f[1:] 499 order = "DESC" 500 else: 501 col_name = f 502 order = "ASC" 503 if "." in col_name: 504 table_prefix, col_name = col_name.split('.', 1) 505 table_prefix = backend.quote_name(table_prefix) + '.' 527 col_name = f 528 order = "ASC" 529 if "." in col_name: 530 table_prefix, col_name = col_name.split('.', 1) 531 table_prefix = backend.quote_name(table_prefix) + '.' 532 else: 533 # Use the database table as a column prefix if it wasn't given, 534 # and if the requested column isn't a custom SELECT. 535 if "." not in col_name and col_name not in (self._select or ()): 536 table_prefix = backend.quote_name(opts.db_table) + '.' 506 537 else: 507 # Use the database table as a column prefix if it wasn't given, 508 # and if the requested column isn't a custom SELECT. 509 if "." not in col_name and col_name not in (self._select or ()): 510 table_prefix = backend.quote_name(opts.db_table) + '.' 511 else: 512 table_prefix = '' 513 order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order)) 538 table_prefix = '' 539 order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order)) 514 540 if order_by: 515 541 sql.append("ORDER BY " + ", ".join(order_by)) 516 542 -
tests/modeltests/ordering/models.py
diff --git a/tests/modeltests/ordering/models.py b/tests/modeltests/ordering/models.py index 110ae3d..8fbcf83 100644
a b The special-case field name ``"?"`` spec 11 11 12 12 The ordering attribute is not required. If you leave it off, ordering will be 13 13 undefined -- not random, just undefined. 14 15 This also applies for models that have a relationship to another model, you 16 can use the name of the related field just like you'd any other field to 17 specify ordering of the model instances in the ``Meta.ordering`` attribute or 18 the ``order_by`` queryset method. 19 20 Another feature is that you can even order it by a field of the related model, 21 for this you use a notation similar to the one used in field lookup, that is 22 ``relationname__fieldname`` (that's a double-underscore). This is only valid 23 in the ``order_by`` queryset method, not in the ``Meta.ordering`` attribute 24 though. 14 25 """ 15 26 16 27 from django.db import models … … class Article(models.Model): 24 35 def __str__(self): 25 36 return self.headline 26 37 38 class ReaderLetter(models.Model): 39 article = models.ForeignKey(Article, null=True) 40 reader_name = models.CharField(maxlength=100) 41 class Meta: 42 #ordering = ('article_headline',) 43 ordering = ('reader_name',) 44 45 def __str__(self): 46 if self.article is None: 47 return self.reader_name 48 else: 49 return "%s, %s" % (self.reader_name, self.article) 50 51 class EditorResponse(models.Model): 52 reader_letter = models.ForeignKey(ReaderLetter) 53 editor_name = models.CharField(maxlength=100) 54 class Meta: 55 ordering = ('editor_name',) 56 57 def __str__(self): 58 return "%s, %s" % (self.editor_name, self.reader_letter) 59 27 60 __test__ = {'API_TESTS':""" 28 61 # Create a couple of Articles. 29 62 >>> from datetime import datetime … … # Use '?' to order randomly. (We're usin 64 97 # don't know what order the output will be in. 65 98 >>> Article.objects.order_by('?') 66 99 [...] 100 101 # Create some reader letters. 102 # First the ones sent as comments about some article. 103 >>> rl1 = ReaderLetter.objects.create(reader_name='Reader D', article=a1) 104 >>> rl2 = ReaderLetter.objects.create(reader_name='Reader D', article=a2) 105 >>> rl3 = ReaderLetter.objects.create(reader_name='Reader C', article=a4) 106 >>> rl4 = ReaderLetter.objects.create(reader_name='Reader B', article=a4) 107 >>> rl5 = ReaderLetter.objects.create(reader_name='Reader A', article=None) 108 109 # By default ReaderLetter.objects.all() orders by the headline 110 # of it's related article ascending. 111 >>> ReaderLetter.objects.all() 112 [<ReaderLetter: Reader A>, <ReaderLetter: Reader B, Article 4>, <ReaderLetter: Reader C, Article 4>, <ReaderLetter: Reader D, Article 1>, <ReaderLetter: Reader D, Article 2>] 113 114 # Composite ordering using the related article headline descending as one of the components 115 >>> ReaderLetter.objects.order_by('reader_name', '-article__headline') 116 [<ReaderLetter: Reader B, Article 4>, <ReaderLetter: Reader C, Article 4>, <ReaderLetter: Reader D, Article 2>, <ReaderLetter: Reader D, Article 1>] 117 118 >>> er1 = EditorResponse.objects.create(editor_name='Editor A', reader_letter=rl1) 119 >>> er2 = EditorResponse.objects.create(editor_name='Editor B', reader_letter=rl2) 120 >>> er3 = EditorResponse.objects.create(editor_name='Editor B', reader_letter=rl3) 121 122 >>> EditorResponse.objects.all() 123 [<EditorResponse: Editor A, Reader D, Article 1>, <EditorResponse: Editor B, Reader D, Article 2>, <EditorResponse: Editor B, Reader C, Article 4>] 124 125 # Order by the PK of related ReaderLetter. 126 >>> EditorResponse.objects.order_by('reader_letter') 127 [<EditorResponse: Editor A, Reader D, Article 1>, <EditorResponse: Editor B, Reader D, Article 2>, <EditorResponse: Editor B, Reader C, Article 4>] 128 129 # Order by another field of the related ReaderLetter object. 130 >>> EditorResponse.objects.order_by('reader_letter__reader_name') 131 [<EditorResponse: Editor B, Reader C, Article 4>, <EditorResponse: Editor A, Reader D, Article 1>, <EditorResponse: Editor B, Reader D, Article 2>] 132 133 # The ordering specification can span models through relationships too. 134 # Order by the PK of the article related to the reader letter related 135 # to the editor response, descending. 136 >>> EditorResponse.objects.order_by('-reader_letter__article') 137 [<EditorResponse: Editor B, Reader C, Article 4>, <EditorResponse: Editor B, Reader D, Article 2>, <EditorResponse: Editor A, Reader D, Article 1>] 138 139 # Order by the article publication date, ascending. 140 >>> EditorResponse.objects.order_by('reader_letter__article__pub_date') 141 [<EditorResponse: Editor A, Reader D, Article 1>, <EditorResponse: Editor B, Reader D, Article 2>, <EditorResponse: Editor B, Reader C, Article 4>] 142 143 # Composite ordering with one of the components being a specification that 144 # spans a FK relationship 145 >>> EditorResponse.objects.order_by('-editor_name', 'reader_letter__article') 146 [<EditorResponse: Editor B, Reader D, Article 2>, <EditorResponse: Editor B, Reader C, Article 4>, <EditorResponse: Editor A, Reader D, Article 1>] 67 147 """}