Django

Code

Ticket #2076: ticket-2076.3.diff

File ticket-2076.3.diff, 8.9 kB (added by mir@noris.de, 1 year ago)

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

  • a/django/db/models/query.py

    old new  
    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]) 
     
    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 
  • a/tests/modeltests/ordering/models.py

    old new  
    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 
     
    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 
     
    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"""}