Ticket #11868: django_admin_multisort.patch

File django_admin_multisort.patch, 8.9 KB (added by Ben Davis, 15 years ago)
  • contrib/admin/media/css/base.css

    Binary files django_trunk/django/conf/global_settings.pyc and django_adminsortable/conf/global_settings.pyc differ
    Binary files django_trunk/django/conf/__init__.pyc and django_adminsortable/conf/__init__.pyc differ
    diff -x .svn -Nur django_trunk/django/contrib/admin/media/css/base.css django_adminsortable/contrib/admin/media/css/base.css
    old new  
    326326    background: url(../img/admin/arrow-up.gif) right .4em no-repeat;
    327327}
    328328
     329table thead th.sorted a span.text {
     330        display: block;
     331        float: left;
     332}
     333table thead th.sorted a span.sort_pos {
     334        display: block;
     335        float: right;
     336        font-size: .6em;
     337}
     338table thead th.sorted a span.clear{
     339        display: block;
     340        clear: both;
     341}
     342
    329343/* ORDERABLE TABLES */
    330344
    331345table.orderable tbody tr td:hover {
  • contrib/admin/templates/admin/change_list_results.html

    diff -x .svn -Nur django_trunk/django/contrib/admin/templates/admin/change_list_results.html django_adminsortable/contrib/admin/templates/admin/change_list_results.html
    old new  
    22<table cellspacing="0">
    33<thead>
    44<tr>
    5 {% for header in result_headers %}<th{{ header.class_attrib }}>
    6 {% if header.sortable %}<a href="{{ header.url }}">{% endif %}
    7 {{ header.text|capfirst }}
    8 {% if header.sortable %}</a>{% endif %}</th>{% endfor %}
     5{% for header in result_headers %}
     6<th{{ header.class_attrib }}>
     7  {% if header.sortable %}<a href="{{ header.url }}">{% endif %}
     8  <span class="text">{{ header.text|capfirst }}</span>
     9  {% if header.sortable %}<span class="sort_pos">{{ header.sort_pos }}</span>
     10  <span class="clear"></span>
     11  </a>{% endif %}
     12</th>{% endfor %}
    913</tr>
    1014</thead>
    1115<tbody>
  • contrib/admin/templatetags/admin_list.py

    diff -x .svn -Nur django_trunk/django/contrib/admin/templatetags/admin_list.py django_adminsortable/contrib/admin/templatetags/admin_list.py
    old new  
    120120
    121121        th_classes = []
    122122        new_order_type = 'asc'
    123         if field_name == cl.order_field or admin_order_field == cl.order_field:
    124             th_classes.append('sorted %sending' % cl.order_type.lower())
    125             new_order_type = {'asc': 'desc', 'desc': 'asc'}[cl.order_type.lower()]
     123        ordering_fields = cl.get_ordering_fields()
     124        sort_pos = ''
     125        if field_name in ordering_fields.keys() or admin_order_field in ordering_fields.keys():
     126            if not field_name in ordering_fields.keys():
     127                field_name = admin_order_field
     128            order_type = ordering_fields.get(field_name).lower()
     129            sort_pos = ordering_fields.keys().index(field_name) + 1
     130            th_classes.append('sorted %sending' % order_type)
     131            new_order_type = {'':'asc', 'asc': 'desc', 'desc': ''}[order_type]
     132       
     133        # build new ordering param
     134        o_list = []
     135        for f in ordering_fields.keys():
     136            try:
     137                n = cl.list_display.index(f)
     138            except ValueError:
     139                continue
     140
     141            if f == field_name:
     142                if new_order_type == '':
     143                    continue
     144                t = new_order_type
     145            else:
     146                t = ordering_fields.get(f)
     147
     148            o_list.append((t=='desc' and '-' or '') + str(n))
     149       
     150        if field_name not in ordering_fields.keys() and new_order_type:
     151            n = cl.list_display.index(field_name)
     152            o_list.append((new_order_type=='desc' and '-' or '') + str(n))
     153
     154        o_list = ','.join(o_list)
    126155
    127156        yield {"text": header,
    128157               "sortable": True,
    129                "url": cl.get_query_string({ORDER_VAR: i, ORDER_TYPE_VAR: new_order_type}),
     158               "sort_pos": sort_pos > 0 and len(ordering_fields) > 0 and unicode(sort_pos) or '',
     159               "url": cl.get_query_string({ORDER_VAR: o_list}),
    130160               "class_attrib": mark_safe(th_classes and ' class="%s"' % ' '.join(th_classes) or '')}
    131161
    132162def _boolean_icon(field_val):
  • contrib/admin/views/main.py

    diff -x .svn -Nur django_trunk/django/contrib/admin/views/main.py django_adminsortable/contrib/admin/views/main.py
    old new  
    44from django.core.paginator import Paginator, InvalidPage
    55from django.db import models
    66from django.db.models.query import QuerySet
     7from django.utils.datastructures import SortedDict
    78from django.utils.encoding import force_unicode, smart_str
    89from django.utils.translation import ugettext
    910from django.utils.http import urlencode
     
    6364        if ERROR_FLAG in self.params:
    6465            del self.params[ERROR_FLAG]
    6566
    66         self.order_field, self.order_type = self.get_ordering()
     67        self.ordering = self.get_ordering()
    6768        self.query = request.GET.get(SEARCH_VAR, '')
    6869        self.query_set = self.get_query_set()
    6970        self.get_results(request)
     
    137138        # those exist, order descending by ID by default. Finally, look for
    138139        # manually-specified ordering from the query string.
    139140        ordering = self.model_admin.ordering or lookup_opts.ordering or ['-' + lookup_opts.pk.name]
    140 
    141         if ordering[0].startswith('-'):
    142             order_field, order_type = ordering[0][1:], 'desc'
    143         else:
    144             order_field, order_type = ordering[0], 'asc'
     141       
    145142        if ORDER_VAR in params:
    146             try:
    147                 field_name = self.list_display[int(params[ORDER_VAR])]
     143            # Clear ordering and used params
     144            ordering = []
     145            order_params = params[ORDER_VAR].split(',')
     146            for p in order_params:
    148147                try:
    149                     f = lookup_opts.get_field(field_name)
    150                 except models.FieldDoesNotExist:
    151                     # See whether field_name is a name of a non-field
    152                     # that allows sorting.
     148                    none, pfx, idx = p.rpartition('-')
     149                    field_name = self.list_display[int(idx)]
    153150                    try:
    154                         if callable(field_name):
    155                             attr = field_name
    156                         elif hasattr(self.model_admin, field_name):
    157                             attr = getattr(self.model_admin, field_name)
    158                         else:
    159                             attr = getattr(self.model, field_name)
    160                         order_field = attr.admin_order_field
    161                     except AttributeError:
    162                         pass
    163                 else:
    164                     order_field = f.name
    165             except (IndexError, ValueError):
    166                 pass # Invalid ordering specified. Just use the default.
    167         if ORDER_TYPE_VAR in params and params[ORDER_TYPE_VAR] in ('asc', 'desc'):
    168             order_type = params[ORDER_TYPE_VAR]
    169         return order_field, order_type
     151                        f = lookup_opts.get_field(field_name)
     152                    except models.FieldDoesNotExist:
     153                        # See whether field_name is a name of a non-field
     154                        # that allows sorting.
     155                        try:
     156                            if callable(field_name):
     157                                attr = field_name
     158                            elif hasattr(self.model_admin, field_name):
     159                                attr = getattr(self.model_admin, field_name)
     160                            else:
     161                                attr = getattr(self.model, field_name)
     162                            field_name = attr.admin_order_field
     163                        except AttributeError:
     164                            pass
     165                    else:
     166                        field_name = f.name
     167
     168                    ordering.append(pfx + field_name)
     169
     170                except (IndexError, ValueError):
     171                    pass # Invalid ordering specified. Skip it.
     172
     173        return ordering
     174   
     175    def get_ordering_fields(self):
     176        # Returns a SortedDict of ordering fields and asc/desc
     177        ordering_fields = SortedDict()
     178        for o in self.ordering:
     179            none, t, f = o.rpartition('-')
     180            ordering_fields[f] = t == '-' and 'desc' or 'asc'
     181        return ordering_fields
    170182
    171183    def get_query_set(self):
    172184        qs = self.root_query_set
     
    214226                            break
    215227
    216228        # Set ordering.
    217         if self.order_field:
    218             qs = qs.order_by('%s%s' % ((self.order_type == 'desc' and '-' or ''), self.order_field))
     229        if self.ordering:
     230            qs = qs.order_by(*self.ordering)
    219231
    220232        # Apply keyword searches.
    221233        def construct_search(field_name):
Back to Top