Ticket #2076: ticket-2076.3.diff

File ticket-2076.3.diff, 8.9 KB (added by mir@…, 12 years ago)

corrected patch without changes in django/newforms/models.py

  • django/db/models/query.py

    a b class QuerySet(object): 
    460460        where.extend(where2)
    461461        params.extend(params2)
    462462
     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
    463491        # Add additional tables and WHERE clauses based on select_related.
    464492        if self._select_related:
    465493            fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table])
    class QuerySet(object): 
    485513            sql.append(where and "WHERE " + " AND ".join(where))
    486514
    487515        # ORDER BY clause
    488         order_by = []
    489516        if self._order_by is not None:
    490517            ordering_to_use = self._order_by
    491518        else:
    492519            ordering_to_use = opts.ordering
     520        if order_by: # dont try to set up ordering again if already done
     521            ordering_to_use = []
    493522        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"
    496526            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) + '.'
    506537                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))
    514540        if order_by:
    515541            sql.append("ORDER BY " + ", ".join(order_by))
    516542
  • 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 
    1111
    1212The ordering attribute is not required. If you leave it off, ordering will be
    1313undefined -- not random, just undefined.
     14
     15This also applies for models that have a relationship to another model, you
     16can use the name of the related field just like you'd any other field to
     17specify ordering of the model instances in the ``Meta.ordering`` attribute or
     18the ``order_by`` queryset method.
     19
     20Another feature is that you can even order it by a field of the related model,
     21for 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
     23in the ``order_by`` queryset method, not in the ``Meta.ordering`` attribute
     24though.
    1425"""
    1526
    1627from django.db import models
    class Article(models.Model): 
    2435    def __str__(self):
    2536        return self.headline
    2637
     38class 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
     51class 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
    2760__test__ = {'API_TESTS':"""
    2861# Create a couple of Articles.
    2962>>> from datetime import datetime
    # Use '?' to order randomly. (We're usin 
    6497# don't know what order the output will be in.
    6598>>> Article.objects.order_by('?')
    6699[...]
     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>]
    67147"""}
Back to Top