Django

Code

Changeset 7285

Show
Ignore:
Timestamp:
03/18/08 05:21:50 (5 months ago)
Author:
mtredinnick
Message:

queryset-refactor: Undo [7220] and allow ordering on multi-valued field.
Some people will shoot themselves in the foot with this. That's bad luck.

The reason we need it is because some data semantics cannot be expressed in
Django's ORM and that shouldn't prevent ordering on that data. For example,
filtering suburbs by a geographic region and then ordering on the suburb names.
The names might not be unique outside that region, but unique inside it. Django
cannot know that (you can't tell the model about it), so we trust the caller.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/queryset-refactor/django/db/models/sql/datastructures.py

    r7235 r7285  
    1010    pass 
    1111 
    12 class JoinError(Exception): 
     12class MultiJoin(Exception): 
     13    """ 
     14    Used by join construction code to indicate the point at which a 
     15    multi-valued join was attempted (if the caller wants to treat that 
     16    exceptionally). 
     17    """ 
    1318    def __init__(self, level): 
    1419        self.level = level 
  • django/branches/queryset-refactor/django/db/models/sql/query.py

    r7283 r7285  
    1919from django.db.models.fields import FieldDoesNotExist 
    2020from django.core.exceptions import FieldError 
    21 from datastructures import EmptyResultSet, Empty, JoinError 
     21from datastructures import EmptyResultSet, Empty, MultiJoin 
    2222from constants import * 
    2323 
     
    524524        if not alias: 
    525525            alias = self.get_initial_alias() 
    526         try: 
    527             field, target, opts, joins, last = self.setup_joins(pieces, opts, 
    528                     alias, False, False) 
    529         except JoinError: 
    530             raise FieldError("Cannot order by many-valued field: '%s'" % name) 
     526        field, target, opts, joins, last = self.setup_joins(pieces, opts, 
     527                alias, False) 
    531528        alias = joins[-1] 
    532529        col = target.column 
     
    849846            field, target, opts, join_list, last = self.setup_joins(parts, opts, 
    850847                    alias, (connector == AND), allow_many) 
    851         except JoinError, e: 
     848        except MultiJoin, e: 
    852849            self.split_exclude(filter_expr, LOOKUP_SEP.join(parts[:e.level])) 
    853850            return 
     
    10081005                for alias in joins: 
    10091006                    self.unref_alias(alias) 
    1010                 raise JoinError(pos + 1) 
     1007                raise MultiJoin(pos + 1) 
    10111008            if model: 
    10121009                # The field lives on a base class of the current model. 
     
    11761173                        True) 
    11771174                self.select.append((joins[-1], target.column)) 
    1178         except JoinError
     1175        except MultiJoin
    11791176            raise FieldError("Invalid field name: '%s'" % name) 
    11801177 
  • django/branches/queryset-refactor/docs/db-api.txt

    r7230 r7285  
    511511...since the ``Blog`` model has no default ordering specified. 
    512512 
    513 You can only order by model fields that have a single value attached to them 
    514 for each instance of the model. For example, non-relations, ``ForeignKey`` and 
    515 ``OneToOneField`` fields. Explicitly, you can't order by a ``ManyToManyField`` 
    516 or a reverse ``ForeignKey`` relation. There's no naturally correct ordering 
    517 for many-valued fields and a lot of the alternatives are not psosible to 
    518 express in SQL very efficiently. 
     513It is permissible to specify a multi-valued field to order the results by (for 
     514example, a ``ManyToMany`` field). Normally this won't be a sensible thing to 
     515do and it's really an advanced usage feature. However, if you know that your 
     516queryset's filtering or available data implies that there will only be one 
     517ordering piece of data for each of the main items you are selecting, the 
     518ordering may well be exactly what you want to do. Use ordering on multi-valued 
     519fields with care and make sure the results are what you expect. 
    519520 
    520521**New in Django development version:** If you don't want any ordering to be 
  • django/branches/queryset-refactor/tests/regressiontests/queries/models.py

    r7247 r7285  
    425425 
    426426# Ordering by a many-valued attribute (e.g. a many-to-many or reverse 
    427 # ForeignKey) doesn't make sense (there's no natural ordering). 
     427# ForeignKey) is legal, but the results might not make sense. That isn't 
     428# Django's problem. Garbage in, garbage out. 
    428429>>> Item.objects.all().order_by('tags') 
    429 Traceback (most recent call last): 
    430 ... 
    431 FieldError: Cannot order by many-valued field: 'tags' 
     430[...] 
    432431 
    433432# If we replace the default ordering, Django adjusts the required tables