Ticket #11868: 11868_luke2.diff
File 11868_luke2.diff, 13.1 KB (added by , 13 years ago) |
---|
-
django/contrib/admin/media/css/base.css
diff -r ca63438cd7b9 django/contrib/admin/media/css/base.css
a b 326 326 background: url(../img/admin/arrow-down.gif) right .4em no-repeat; 327 327 } 328 328 329 table thead th.sorted a span.text { 330 display: block; 331 float: left; 332 } 333 334 table thead th.sorted a span.sortpos { 335 display: block; 336 float: right; 337 font-size: .6em; 338 } 339 340 table thead th.sorted a img { 341 vertical-align: bottom; 342 /* Make it look like a link */ 343 border-bottom: 1px solid #5b80b2; 344 } 345 346 table thead th.sorted a span.clear { 347 display: block; 348 clear: both; 349 } 350 351 #sorting-popup-div { 352 position: absolute; 353 background-color: white; 354 border: 1px solid #ddd; 355 z-index: 2000; /* more than filters on right */ 356 padding-right: 10px; 357 } 358 329 359 /* ORDERABLE TABLES */ 330 360 331 361 table.orderable tbody tr td:hover { -
django/contrib/admin/templates/admin/change_list_results.html
diff -r ca63438cd7b9 django/contrib/admin/templates/admin/change_list_results.html
a b 1 {% load adminmedia %} 2 {% load i18n %} 1 3 {% if result_hidden_fields %} 2 4 <div class="hiddenfields">{# DIV for HTML validation #} 3 5 {% for item in result_hidden_fields %}{{ item }}{% endfor %} … … 8 10 <table id="result_list"> 9 11 <thead> 10 12 <tr> 11 {% for header in result_headers %}<th scope="col"{{ header.class_attrib }}> 12 {% if header.sortable %}<a href="{{ header.url }}">{% endif %} 13 {{ header.text|capfirst }} 14 {% if header.sortable %}</a>{% endif %}</th>{% endfor %} 13 {% for header in result_headers %} 14 <th scope="col" {{ header.class_attrib }}> 15 {% if header.sortable %}<a href="{{ header.url }}">{% endif %} 16 <span class="text">{{ header.text|capfirst }}</span> 17 {% if header.sortable %} 18 {% if header.sort_pos > 0 %}<span class="sortpos"> 19 {% if header.sort_pos == 1 %}<img id="primary-sort-icon" src="{% admin_media_prefix %}img/admin/icon_primary_sort.png" alt="Primary sort field" />{% endif %} 20 {{ header.sort_pos }}</span> 21 {% endif %} 22 <span class="clear"></span></a> 23 {% endif %} 24 </th>{% endfor %} 15 25 </tr> 16 26 </thead> 17 27 <tbody> … … 24 34 </tbody> 25 35 </table> 26 36 </div> 37 38 {# Sorting popup: #} 39 <div style="display: none;" id="sorting-popup-div"> 40 <p>{% trans "Sorting by:" %}</p> 41 <ol> 42 {% for header in result_headers|dictsort:"sort_pos" %} 43 {% if header.sort_pos > 0 %} 44 <li>{{ header.text|capfirst }}</li> 45 {% endif %} 46 {% endfor %} 47 </ol> 48 <p><a href="{{ reset_order_url }}">{% trans "Reset sorting" %}</a></p> 49 </div> 50 <script type="text/javascript"> 51 <!-- 52 (function($) { 53 $(document).ready(function() { 54 var popup = $('#sorting-popup-div'); 55 /* These next lines seems necessary to prime the popup: */ 56 popup.offset({left:-1000, top:0}); 57 popup.show(); 58 var popupWidth = popup.width() 59 popup.hide(); 60 61 $('#primary-sort-icon').toggle(function(ev) { 62 ev.preventDefault(); 63 var img = $(this); 64 var pos = img.offset(); 65 pos.top += img.height(); 66 if (pos.left + popupWidth > 67 $(window).width()) { 68 pos.left -= popupWidth; 69 } 70 popup.show(); 71 popup.offset(pos); 72 }, 73 function(ev) { 74 ev.preventDefault(); 75 popup.hide(); 76 }); 77 }); 78 })(django.jQuery); 79 //--> 80 </script> 81 27 82 {% endif %} -
django/contrib/admin/templatetags/admin_list.py
diff -r ca63438cd7b9 django/contrib/admin/templatetags/admin_list.py
a b 93 93 if field_name == 'action_checkbox': 94 94 yield { 95 95 "text": header, 96 "sort_pos": 0, 96 97 "class_attrib": mark_safe(' class="action-checkbox-column"') 97 98 } 98 99 continue … … 100 101 # It is a non-field, but perhaps one that is sortable 101 102 admin_order_field = getattr(attr, "admin_order_field", None) 102 103 if not admin_order_field: 103 yield {"text": header }104 yield {"text": header, "sort_pos": 0 } 104 105 continue 105 106 106 107 # So this _is_ a sortable non-field. Go to the yield … … 110 111 111 112 th_classes = [] 112 113 new_order_type = 'asc' 113 if field_name == cl.order_field or admin_order_field == cl.order_field: 114 th_classes.append('sorted %sending' % cl.order_type.lower()) 115 new_order_type = {'asc': 'desc', 'desc': 'asc'}[cl.order_type.lower()] 114 ordering_fields = cl.get_ordering_fields() 115 sort_pos = 0 116 if field_name in ordering_fields or admin_order_field in ordering_fields: 117 if not field_name in ordering_fields: 118 field_name = admin_order_field 119 order_type = ordering_fields.get(field_name).lower() 120 sort_pos = ordering_fields.keys().index(field_name) + 1 121 th_classes.append('sorted %sending' % order_type) 122 new_order_type = {'asc': 'desc', 'desc': 'asc'}[order_type] 123 124 # build new ordering param 125 o_list = [] 126 make_qs_param = lambda t, n: ('-' if t == 'desc' else '') + str(n) 127 128 for f in ordering_fields.keys(): 129 try: 130 n = cl.list_display.index(f) 131 except ValueError: 132 continue 133 134 if f == field_name: 135 # We want clicking on this header to bring the ordering to the 136 # front 137 o_list.insert(0, make_qs_param(new_order_type, n)) 138 else: 139 o_list.append(make_qs_param(ordering_fields.get(f), n)) 140 141 if field_name not in ordering_fields: 142 n = cl.list_display.index(field_name) 143 o_list.insert(0, make_qs_param(new_order_type, n)) 144 145 o_list = '.'.join(o_list) 116 146 117 147 yield { 118 148 "text": header, 119 149 "sortable": True, 120 "url": cl.get_query_string({ORDER_VAR: i, ORDER_TYPE_VAR: new_order_type}), 150 "sort_pos": sort_pos, 151 "url": cl.get_query_string({ORDER_VAR: o_list}), 121 152 "class_attrib": mark_safe(th_classes and ' class="%s"' % ' '.join(th_classes) or '') 122 153 } 123 154 … … 231 262 return {'cl': cl, 232 263 'result_hidden_fields': list(result_hidden_fields(cl)), 233 264 'result_headers': list(result_headers(cl)), 265 'reset_order_url': cl.get_query_string(remove=[ORDER_VAR]), 234 266 'results': list(results(cl))} 235 267 236 268 @register.inclusion_tag('admin/date_hierarchy.html') -
django/contrib/admin/views/main.py
diff -r ca63438cd7b9 django/contrib/admin/views/main.py
a b 3 3 from django.core.exceptions import SuspiciousOperation 4 4 from django.core.paginator import InvalidPage 5 5 from django.db import models 6 from django.utils.datastructures import SortedDict 6 7 from django.utils.encoding import force_unicode, smart_str 7 8 from django.utils.translation import ugettext, ugettext_lazy 8 9 from django.utils.http import urlencode … … 75 76 self.list_editable = () 76 77 else: 77 78 self.list_editable = list_editable 78 self.order _field, self.order_type= self.get_ordering()79 self.ordering = self.get_ordering() 79 80 self.query = request.GET.get(SEARCH_VAR, '') 80 81 self.query_set = self.get_query_set(request) 81 82 self.get_results(request) … … 171 172 # manually-specified ordering from the query string. 172 173 ordering = self.model_admin.ordering or lookup_opts.ordering or ['-' + lookup_opts.pk.name] 173 174 174 if ordering[0].startswith('-'):175 order_field, order_type = ordering[0][1:], 'desc'176 else:177 order_field, order_type = ordering[0], 'asc'178 175 if ORDER_VAR in params: 179 try: 180 field_name = self.list_display[int(params[ORDER_VAR])] 176 # Clear ordering and used params 177 ordering = [] 178 order_params = params[ORDER_VAR].split('.') 179 for p in order_params: 181 180 try: 182 f = lookup_opts.get_field(field_name) 183 except models.FieldDoesNotExist: 184 # See whether field_name is a name of a non-field 185 # that allows sorting. 181 none, pfx, idx = p.rpartition('-') 182 field_name = self.list_display[int(idx)] 186 183 try: 187 if callable(field_name): 188 attr = field_name 189 elif hasattr(self.model_admin, field_name): 190 attr = getattr(self.model_admin, field_name) 191 else: 192 attr = getattr(self.model, field_name) 193 order_field = attr.admin_order_field 194 except AttributeError: 195 pass 196 else: 197 order_field = f.name 198 except (IndexError, ValueError): 199 pass # Invalid ordering specified. Just use the default. 200 if ORDER_TYPE_VAR in params and params[ORDER_TYPE_VAR] in ('asc', 'desc'): 201 order_type = params[ORDER_TYPE_VAR] 202 return order_field, order_type 184 f = lookup_opts.get_field(field_name) 185 except models.FieldDoesNotExist: 186 # See whether field_name is a name of a non-field 187 # that allows sorting. 188 try: 189 if callable(field_name): 190 attr = field_name 191 elif hasattr(self.model_admin, field_name): 192 attr = getattr(self.model_admin, field_name) 193 else: 194 attr = getattr(self.model, field_name) 195 field_name = attr.admin_order_field 196 except AttributeError: 197 pass 198 else: 199 field_name = f.name 200 201 ordering.append(pfx + field_name) 202 203 except (IndexError, ValueError): 204 pass # Invalid ordering specified. Skip it. 205 206 return ordering 207 208 def get_ordering_fields(self): 209 # Returns a SortedDict of ordering fields and asc/desc 210 ordering_fields = SortedDict() 211 for o in self.ordering: 212 none, t, f = o.rpartition('-') 213 ordering_fields[f] = 'desc' if t == '-' else 'asc' 214 return ordering_fields 203 215 204 216 def get_lookup_params(self, use_distinct=False): 205 217 lookup_params = self.params.copy() # a dictionary of the query string … … 290 302 break 291 303 292 304 # Set ordering. 293 if self.order _field:294 qs = qs.order_by( '%s%s' % ((self.order_type == 'desc' and '-' or ''), self.order_field))305 if self.ordering: 306 qs = qs.order_by(*self.ordering) 295 307 296 308 # Apply keyword searches. 297 309 def construct_search(field_name): -
docs/ref/contrib/admin/index.txt
diff -r ca63438cd7b9 docs/ref/contrib/admin/index.txt
a b 696 696 If this isn't provided, the Django admin will use the model's default 697 697 ordering. 698 698 699 .. admonition:: Note700 701 Django will only honor the first element in the list/tuple;any others702 will be ignored.699 .. versionchanged:: 1.4 700 701 Django honors all elements in the list/tuple; before 1.4, any others 702 were ignored. 703 703 704 704 .. attribute:: ModelAdmin.paginator 705 705 -
docs/releases/1.4.txt
diff -r ca63438cd7b9 docs/releases/1.4.txt
a b 46 46 known as "FilterSpec" which was used internally. For more details, see the 47 47 documentation for :attr:`~django.contrib.admin.ModelAdmin.list_filter`. 48 48 49 Multiple sort in admin interface 50 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 51 52 The admin change list now supports sorting on multiple columns. It respects all 53 elements of the :attr:`~django.contrib.admin.ModelAdmin.ordering` attribute, and 54 sorting on multiple columns by clicking on headers is designed to work similarly 55 to how desktop GUIs do it. 56 49 57 Tools for cryptographic signing 50 58 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 51 59