Fixed #3397: You can now order by non-DB fields in the admin by telling Django which field to actually order by. Thanks, marcink@elksoft.pl
git-svn-id: http://code.djangoproject.com/svn/django/trunk@4596 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
3d164ab04f
commit
abf79841fe
|
@ -84,22 +84,31 @@ def result_headers(cl):
|
|||
header = attr.short_description
|
||||
except AttributeError:
|
||||
header = field_name.replace('_', ' ')
|
||||
# Non-field list_display values don't get ordering capability.
|
||||
yield {"text": header}
|
||||
|
||||
# It is a non-field, but perhaps one that is sortable
|
||||
if not getattr(getattr(cl.model, field_name), "admin_order_field", None):
|
||||
yield {"text": header}
|
||||
continue
|
||||
|
||||
# So this _is_ a sortable non-field. Go to the yield
|
||||
# after the else clause.
|
||||
else:
|
||||
if isinstance(f.rel, models.ManyToOneRel) and f.null:
|
||||
yield {"text": f.verbose_name}
|
||||
continue
|
||||
else:
|
||||
th_classes = []
|
||||
new_order_type = 'asc'
|
||||
if field_name == cl.order_field:
|
||||
th_classes.append('sorted %sending' % cl.order_type.lower())
|
||||
new_order_type = {'asc': 'desc', 'desc': 'asc'}[cl.order_type.lower()]
|
||||
header = f.verbose_name
|
||||
|
||||
yield {"text": f.verbose_name,
|
||||
"sortable": True,
|
||||
"url": cl.get_query_string({ORDER_VAR: i, ORDER_TYPE_VAR: new_order_type}),
|
||||
"class_attrib": (th_classes and ' class="%s"' % ' '.join(th_classes) or '')}
|
||||
th_classes = []
|
||||
new_order_type = 'asc'
|
||||
if field_name == cl.order_field:
|
||||
th_classes.append('sorted %sending' % cl.order_type.lower())
|
||||
new_order_type = {'asc': 'desc', 'desc': 'asc'}[cl.order_type.lower()]
|
||||
|
||||
yield {"text": header,
|
||||
"sortable": True,
|
||||
"url": cl.get_query_string({ORDER_VAR: i, ORDER_TYPE_VAR: new_order_type}),
|
||||
"class_attrib": (th_classes and ' class="%s"' % ' '.join(th_classes) or '')}
|
||||
|
||||
def _boolean_icon(field_val):
|
||||
BOOLEAN_MAPPING = {True: 'yes', False: 'no', None: 'unknown'}
|
||||
|
|
|
@ -655,10 +655,17 @@ class ChangeList(object):
|
|||
order_field, order_type = ordering[0], 'asc'
|
||||
if params.has_key(ORDER_VAR):
|
||||
try:
|
||||
field_name = lookup_opts.admin.list_display[int(params[ORDER_VAR])]
|
||||
try:
|
||||
f = lookup_opts.get_field(lookup_opts.admin.list_display[int(params[ORDER_VAR])])
|
||||
f = lookup_opts.get_field(field_name)
|
||||
except models.FieldDoesNotExist:
|
||||
pass
|
||||
# see if field_name is a name of a non-field
|
||||
# that allows sorting
|
||||
try:
|
||||
attr = getattr(lookup_opts.admin.manager.model, field_name)
|
||||
order_field = attr.admin_order_field
|
||||
except IndexError:
|
||||
pass
|
||||
else:
|
||||
if not isinstance(f.rel, models.ManyToOneRel) or not f.null:
|
||||
order_field = f.name
|
||||
|
|
|
@ -1295,10 +1295,30 @@ A few special cases to note about ``list_display``:
|
|||
|
||||
list_display = ('__str__', 'some_other_field')
|
||||
|
||||
* For any element of ``list_display`` that is not a field on the model, the
|
||||
change list page will not allow ordering by that column. This is because
|
||||
ordering is done at the database level, and Django has no way of knowing
|
||||
how to order the result of a custom method at the SQL level.
|
||||
* Usually, elements of ``list_display`` that aren't actual database fields
|
||||
can't be used in sorting (because Django does all the sorting at the
|
||||
database level).
|
||||
|
||||
However, if an element of ``list_display`` represents a certain database
|
||||
field, you can indicate this fact by setting the ``admin_order_field``
|
||||
attribute of the item.
|
||||
|
||||
For example::
|
||||
|
||||
class Person(models.Model):
|
||||
first_name = models.CharField(maxlength=50)
|
||||
color_code = models.CharField(maxlength=6)
|
||||
|
||||
class Admin:
|
||||
list_display = ('first_name', 'colored_first_name')
|
||||
|
||||
def colored_first_name(self):
|
||||
return '<span style="color: #%s;">%s</span>' % (self.color_code, self.first_name)
|
||||
colored_first_name.allow_tags = True
|
||||
colored_first_name.admin_order_field = 'first_name'
|
||||
|
||||
The above will tell Django to order by the ``first_name`` field when
|
||||
trying to sort by ``colored_first_name`` in the admin.
|
||||
|
||||
``list_display_links``
|
||||
----------------------
|
||||
|
|
Loading…
Reference in New Issue