diff -rN -u old-ticket2076.5/django/core/management.py new-ticket2076.5/django/core/management.py
--- old-ticket2076.5/django/core/management.py	2007-02-28 07:40:19.000000000 -0300
+++ new-ticket2076.5/django/core/management.py	2007-02-28 07:40:20.000000000 -0300
@@ -1033,7 +1033,9 @@
                     field_name = field_name[1:]
                 if opts.order_with_respect_to and field_name == '_order':
                     continue
-                if '.' in field_name: continue # Skip ordering in the format 'table.field'.
+                if '.' in field_name: # Reject ordering in the format 'table.field'.
+                    e.add(opts, '"ordering" has "%s" which uses a format not supported anymore. Use field names and \'__\' instead.' % field_name)
+                if '__' in field_name: continue # Skip ordering in the format 'relation__related_model_field'.
                 try:
                     opts.get_field(field_name, many_to_many=False)
                 except models.FieldDoesNotExist:
diff -rN -u old-ticket2076.5/django/db/models/query.py new-ticket2076.5/django/db/models/query.py
--- old-ticket2076.5/django/db/models/query.py	2007-02-28 07:40:19.000000000 -0300
+++ new-ticket2076.5/django/db/models/query.py	2007-02-28 07:40:20.000000000 -0300
@@ -471,6 +471,34 @@
         where.extend(where2)
         params.extend(params2)
 
+        # Resolve order_by dependencies before joins to order by related tables
+        order_by = []
+        if self._order_by is not None: # use order_by = () to disable ordering
+            ordering_to_use = self._order_by
+        else:
+            ordering_to_use = opts.ordering
+
+        for f in handle_legacy_orderlist(ordering_to_use):
+            if "." in f: # dot-style field, fall back to old ordering code below
+                order_by = []
+                break
+            elif f == '?': # Special case.
+                order_by.append(backend.get_random_function_sql())
+                break
+            elif f.startswith('-'):
+                path = f[1:].split(LOOKUP_SEPARATOR)
+                order = "DESC"
+            else:
+                path = f.split(LOOKUP_SEPARATOR)
+                order = "ASC"
+
+            joins3, where3, params3 = lookup_inner(path, 'exact', False, opts, opts.db_table, None)
+            joins.update(joins3)
+
+            # hack to get fieldname to order by. modify lookup_inner to supply this instead.
+            field = where3[0].replace(' = %s', '')
+            order_by.append('%s %s' % (field, order))
+
         # Add additional tables and WHERE clauses based on select_related.
         if self._select_related:
             fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table])
@@ -496,32 +524,26 @@
             sql.append(where and "WHERE " + " AND ".join(where))
 
         # ORDER BY clause
-        order_by = []
         if self._order_by is not None:
             ordering_to_use = self._order_by
         else:
             ordering_to_use = opts.ordering
+        if order_by: # dont try to set up ordering again if already done
+            ordering_to_use = []
         for f in handle_legacy_orderlist(ordering_to_use):
-            if f == '?': # Special case.
-                order_by.append(backend.get_random_function_sql())
+            if f.startswith('-'):
+                col_name = f[1:]
+                order = "DESC"
+            else:
+                col_name = f
+                order = "ASC"
+            # Use the database table as a column prefix if it wasn't given,
+            # and if the requested column isn't a custom SELECT.
+            if col_name not in (self._select or ()):
+                table_prefix = backend.quote_name(opts.db_table) + '.'
             else:
-                if f.startswith('-'):
-                    col_name = f[1:]
-                    order = "DESC"
-                else:
-                    col_name = f
-                    order = "ASC"
-                if "." in col_name:
-                    table_prefix, col_name = col_name.split('.', 1)
-                    table_prefix = backend.quote_name(table_prefix) + '.'
-                else:
-                    # Use the database table as a column prefix if it wasn't given,
-                    # and if the requested column isn't a custom SELECT.
-                    if "." not in col_name and col_name not in (self._select or ()):
-                        table_prefix = backend.quote_name(opts.db_table) + '.'
-                    else:
-                        table_prefix = ''
-                order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order))
+                table_prefix = ''
+            order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order))
         if order_by:
             sql.append("ORDER BY " + ", ".join(order_by))
 
diff -rN -u old-ticket2076.5/docs/db-api.txt new-ticket2076.5/docs/db-api.txt
--- old-ticket2076.5/docs/db-api.txt	2007-02-28 07:40:19.000000000 -0300
+++ new-ticket2076.5/docs/db-api.txt	2007-02-28 07:40:21.000000000 -0300
@@ -420,10 +420,17 @@
 
     Entry.objects.order_by('?')
 
-To order by a field in a different table, add the other table's name and a dot,
-like so::
+**New in Django development version:** To order by a field in a related model,
+use the relationship name and the field name separated by ``__`` (that's a
+double-underscore) using a notation that resembles the notation used in
+`Field lookups`_::
 
-    Entry.objects.order_by('blogs_blog.name', 'headline')
+    Entry.objects.order_by('blog__name', 'headline')
+
+This can also span more than one relationships, both many-to-one and
+many-to-many and both forward and backwards::
+
+    Blog.objects.order_by('entry__authors__name')
 
 There's no way to specify whether ordering should be case sensitive. With
 respect to case-sensitivity, Django will order results however your database
diff -rN -u old-ticket2076.5/tests/modeltests/ordering/models.py new-ticket2076.5/tests/modeltests/ordering/models.py
--- old-ticket2076.5/tests/modeltests/ordering/models.py	2007-02-28 07:40:19.000000000 -0300
+++ new-ticket2076.5/tests/modeltests/ordering/models.py	2007-02-28 07:40:21.000000000 -0300
@@ -11,6 +11,15 @@
 
 The ordering attribute is not required. If you leave it off, ordering will be
 undefined -- not random, just undefined.
+
+This also applies for models that have a relationship to another model, you
+can use the name of the related field just like you'd any other field to
+specify ordering of the model instances in the ``Meta.ordering`` attribute or
+the ``order_by`` queryset method.
+
+Another feature is that you can even order by a field of the related model,
+for this you use a notation similar to the one used in field lookup, that is
+``relationname__fieldname`` (that's a double-underscore).
 """
 
 from django.db import models
@@ -24,6 +33,40 @@
     def __str__(self):
         return self.headline
 
+class ReaderLetter(models.Model):
+    article = models.ForeignKey(Article, null=True)
+    reader_name = models.CharField(maxlength=100)
+    date_sent = models.DateTimeField()
+    class Meta:
+        ordering = ('reader_name',)
+
+    def __str__(self):
+    	if self.article is None:
+            return self.reader_name
+	else:
+            return "%s, %s" % (self.reader_name, self.article)
+
+class EditorResponse(models.Model):
+    reader_letter = models.ForeignKey(ReaderLetter)
+    editor_name = models.CharField(maxlength=100)
+    class Meta:
+        ordering = ('editor_name',)
+
+    def __str__(self):
+        return "%s, %s" % (self.editor_name, self.reader_letter)
+
+class Reporter(models.Model):
+    name = models.CharField(maxlength=30)
+    articles = models.ManyToManyField(Article)
+    class Meta:
+        ordering = ('articles__headline',)
+
+    def __str__(self):
+        r = "%s" % (self.name)
+        if self.articles.count():
+            r += '; articles: %s' % ', '.join([str(a) for a in self.articles.all()])
+        return r
+
 __test__ = {'API_TESTS':"""
 # Create a couple of Articles.
 >>> from datetime import datetime
@@ -64,4 +107,86 @@
 # don't know what order the output will be in.
 >>> Article.objects.order_by('?')
 [...]
+
+# Create some reader letters.
+# First the ones sent as comments about some article.
+>>> rl1 = ReaderLetter.objects.create(reader_name='Reader D', article=a1, date_sent=(datetime(2005, 8, 5)))
+>>> rl2 = ReaderLetter.objects.create(reader_name='Reader D', article=a2, date_sent=(datetime(2005, 8, 4)))
+>>> rl3 = ReaderLetter.objects.create(reader_name='Reader C', article=a4, date_sent=(datetime(2005, 8, 3)))
+>>> rl4 = ReaderLetter.objects.create(reader_name='Reader B', article=a4, date_sent=(datetime(2005, 8, 2)))
+>>> rl5 = ReaderLetter.objects.create(reader_name='Reader A', article=None, date_sent=(datetime(2005, 8, 1)))
+
+# By default ReaderLetter.objects.all() orders by the name
+# of the reader that wrote it ascending.
+>>> ReaderLetter.objects.all()
+[<ReaderLetter: Reader A>, <ReaderLetter: Reader B, Article 4>, <ReaderLetter: Reader C, Article 4>, <ReaderLetter: Reader D, Article 1>, <ReaderLetter: Reader D, Article 2>]
+
+# Composite ordering using the related article headline descending as one of the components
+>>> ReaderLetter.objects.order_by('reader_name', '-article__headline')
+[<ReaderLetter: Reader B, Article 4>, <ReaderLetter: Reader C, Article 4>, <ReaderLetter: Reader D, Article 2>, <ReaderLetter: Reader D, Article 1>]
+
+>>> er1 = EditorResponse.objects.create(editor_name='Editor A', reader_letter=rl1)
+>>> er2 = EditorResponse.objects.create(editor_name='Editor B', reader_letter=rl2)
+>>> er3 = EditorResponse.objects.create(editor_name='Editor B', reader_letter=rl3)
+
+>>> EditorResponse.objects.all()
+[<EditorResponse: Editor A, Reader D, Article 1>, <EditorResponse: Editor B, Reader D, Article 2>, <EditorResponse: Editor B, Reader C, Article 4>]
+
+# Order just by the relationship field, this should order by the natural
+# ordering of the ReaderLetter model (i.e. as dictated by its Meta.ordering),
+# but right now is ordering by the ReaderLetter PK.
+>>> EditorResponse.objects.order_by('reader_letter')
+[<EditorResponse: Editor A, Reader D, Article 1>, <EditorResponse: Editor B, Reader D, Article 2>, <EditorResponse: Editor B, Reader C, Article 4>]
+
+# Order by another field of the related ReaderLetter object.
+>>> EditorResponse.objects.order_by('reader_letter__reader_name')
+[<EditorResponse: Editor B, Reader C, Article 4>, <EditorResponse: Editor A, Reader D, Article 1>, <EditorResponse: Editor B, Reader D, Article 2>]
+
+# The ordering specification can span models through relationships too.
+# Order by the PK of the article related to the reader letter related
+# to the editor response, descending.
+>>> EditorResponse.objects.order_by('-reader_letter__article')
+[<EditorResponse: Editor B, Reader C, Article 4>, <EditorResponse: Editor B, Reader D, Article 2>, <EditorResponse: Editor A, Reader D, Article 1>]
+
+# Order by the article publication date, ascending.
+>>> EditorResponse.objects.order_by('reader_letter__article__pub_date')
+[<EditorResponse: Editor A, Reader D, Article 1>, <EditorResponse: Editor B, Reader D, Article 2>, <EditorResponse: Editor B, Reader C, Article 4>]
+
+# Composite ordering with one of the components being a specification that
+# spans a FK relationship
+>>> EditorResponse.objects.order_by('-editor_name', 'reader_letter__article')
+[<EditorResponse: Editor B, Reader D, Article 2>, <EditorResponse: Editor B, Reader C, Article 4>, <EditorResponse: Editor A, Reader D, Article 1>]
+
+# Test many-to-many relationships
+>>> r1 = Reporter.objects.create(name='John')
+>>> r2 = Reporter.objects.create(name='Jane')
+>>> r3 = Reporter.objects.create(name='Paul')
+
+>>> r1.articles = [a1, a2]
+>>> r2.articles = [a4, a3]
+>>> r3.articles = [a4, a2]
+
+# The natural ordering of the Reporter model as dictated by its
+# `Meta.ordering` option is by 'article__headline' (i.e. by a field of a
+# related model)
+>>> Reporter.objects.all().distinct()
+[<Reporter: John; articles: Article 2, Article 1>, <Reporter: Paul; articles: Article 4, Article 2>, <Reporter: Jane; articles: Article 4, Article 3>]
+
+# Order by a a related model of a many-to-many relationship. Remember the
+# Article model natural ordering as dictated by its `Meta.ordering`
+# option is ('-pub_date', 'headline')
+>>> Reporter.objects.distinct().order_by('articles')
+[<Reporter: John; articles: Article 2, Article 1>, <Reporter: Paul; articles: Article 4, Article 2>, <Reporter: Jane; articles: Article 4, Article 3>]
+
+# Order the reporters by the headlines of the articles they contributed
+# to, descending
+>>> Reporter.objects.distinct().order_by('-articles__headline')
+[<Reporter: Jane; articles: Article 4, Article 3>, <Reporter: Paul; articles: Article 4, Article 2>, <Reporter: John; articles: Article 2, Article 1>]
+
+# Note how the ordering can also span backward relationships. Here we order
+# the reporters by the date the letter in response to the articles she/he
+# contributed to was sent (if any)
+>>> Reporter.objects.distinct().order_by('articles__readerletter__date_sent')
+[<Reporter: Jane; articles: Article 4, Article 3>, <Reporter: Paul; articles: Article 4, Article 2>, <Reporter: John; articles: Article 2, Article 1>]
+
 """}

