Ticket #6396: ticket_6396.patch
File ticket_6396.patch, 18.3 KB (added by , 17 years ago) |
---|
-
django/contrib/admin/options.py
diff -r 76df9804bd63 -r 577c34da6045 django/contrib/admin/options.py
a b class ModelAdmin(BaseModelAdmin): 627 627 'title': cl.title, 628 628 'is_popup': cl.is_popup, 629 629 'cl': cl, 630 'result_headers': list(cl.result_headers()), 631 'results': list(cl.results()), 630 632 }) 631 633 c.update({'has_add_permission': self.has_add_permission(request)}), 632 634 return render_to_response(['admin/%s/%s/change_list.html' % (app_label, opts.object_name.lower()), -
django/contrib/admin/templates/admin/change_list.html
diff -r 76df9804bd63 -r 577c34da6045 django/contrib/admin/templates/admin/change_list.html
a b 33 33 {% endif %} 34 34 {% endblock %} 35 35 36 {% block result_list %}{% result_list cl %}{% endblock %} 36 {% block result_list %} 37 {% if results %} 38 <table cellspacing="0"> 39 <thead> 40 <tr> 41 {% for header in result_headers %}<th{{ header.class_attrib }}> 42 {% if header.sortable %}<a href="{{ header.url }}">{% endif %} 43 {{ header.text|capfirst }} 44 {% if header.sortable %}</a>{% endif %}</th>{% endfor %} 45 </tr> 46 </thead> 47 <tbody> 48 {% for result in results %} 49 <tr class="{% cycle 'row1' 'row2' %}">{% for item in result %}{{ item }}{% endfor %}</tr> 50 {% endfor %} 51 </tbody> 52 </table> 53 {% endif %} 54 {% endblock %} 55 37 56 {% block pagination %}{% pagination cl %}{% endblock %} 38 57 </div> 39 58 </div> -
deleted file django/contrib/admin/templates/admin/change_list_results.html
diff -r 76df9804bd63 -r 577c34da6045 django/contrib/admin/templates/admin/change_list_results.html
+ - 1 {% if results %}2 <table cellspacing="0">3 <thead>4 <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 %}9 </tr>10 </thead>11 <tbody>12 {% for result in results %}13 <tr class="{% cycle 'row1' 'row2' %}">{% for item in result %}{{ item }}{% endfor %}</tr>14 {% endfor %}15 </tbody>16 </table>17 {% endif %} -
django/contrib/admin/templatetags/admin_list.py
diff -r 76df9804bd63 -r 577c34da6045 django/contrib/admin/templatetags/admin_list.py
a b from django.conf import settings 1 1 from django.conf import settings 2 2 from django.contrib.admin.views.main import ALL_VAR, EMPTY_CHANGELIST_VALUE 3 3 from django.contrib.admin.views.main import ORDER_VAR, ORDER_TYPE_VAR, PAGE_VAR, SEARCH_VAR 4 from django.core.exceptions import ObjectDoesNotExist5 4 from django.db import models 6 5 from django.utils import dateformat 7 from django.utils.html import escape, conditional_escape8 from django.utils.text import capfirst9 6 from django.utils.safestring import mark_safe 10 7 from django.utils.translation import get_date_formats, get_partial_date_formats, ugettext as _ 11 from django.utils.encoding import smart_unicode, smart_str, force_unicode12 8 from django.template import Library 13 9 import datetime 14 10 … … def pagination(cl): 68 64 } 69 65 pagination = register.inclusion_tag('admin/pagination.html')(pagination) 70 66 71 def result_headers(cl):72 lookup_opts = cl.lookup_opts73 74 for i, field_name in enumerate(cl.list_display):75 try:76 f = lookup_opts.get_field(field_name)77 admin_order_field = None78 except models.FieldDoesNotExist:79 # For non-field list_display values, check for the function80 # attribute "short_description". If that doesn't exist, fall back81 # to the method name. And __str__ and __unicode__ are special-cases.82 if field_name == '__unicode__':83 header = force_unicode(lookup_opts.verbose_name)84 elif field_name == '__str__':85 header = smart_str(lookup_opts.verbose_name)86 else:87 attr = getattr(cl.model, field_name) # Let AttributeErrors propagate.88 try:89 header = attr.short_description90 except AttributeError:91 header = field_name.replace('_', ' ')92 93 # It is a non-field, but perhaps one that is sortable94 admin_order_field = getattr(getattr(cl.model, field_name), "admin_order_field", None)95 if not admin_order_field:96 yield {"text": header}97 continue98 99 # So this _is_ a sortable non-field. Go to the yield100 # after the else clause.101 else:102 if isinstance(f.rel, models.ManyToOneRel) and f.null:103 yield {"text": f.verbose_name}104 continue105 else:106 header = f.verbose_name107 108 th_classes = []109 new_order_type = 'asc'110 if field_name == cl.order_field or admin_order_field == cl.order_field:111 th_classes.append('sorted %sending' % cl.order_type.lower())112 new_order_type = {'asc': 'desc', 'desc': 'asc'}[cl.order_type.lower()]113 114 yield {"text": header,115 "sortable": True,116 "url": cl.get_query_string({ORDER_VAR: i, ORDER_TYPE_VAR: new_order_type}),117 "class_attrib": mark_safe(th_classes and ' class="%s"' % ' '.join(th_classes) or '')}118 119 67 def _boolean_icon(field_val): 120 68 BOOLEAN_MAPPING = {True: 'yes', False: 'no', None: 'unknown'} 121 69 return mark_safe(u'<img src="%simg/admin/icon-%s.gif" alt="%s" />' % (settings.ADMIN_MEDIA_PREFIX, BOOLEAN_MAPPING[field_val], field_val)) 122 123 def items_for_result(cl, result):124 first = True125 pk = cl.lookup_opts.pk.attname126 for field_name in cl.list_display:127 row_class = ''128 try:129 f = cl.lookup_opts.get_field(field_name)130 except models.FieldDoesNotExist:131 # For non-field list_display values, the value is either a method132 # or a property.133 try:134 attr = getattr(result, field_name)135 allow_tags = getattr(attr, 'allow_tags', False)136 boolean = getattr(attr, 'boolean', False)137 if callable(attr):138 attr = attr()139 if boolean:140 allow_tags = True141 result_repr = _boolean_icon(attr)142 else:143 result_repr = smart_unicode(attr)144 except (AttributeError, ObjectDoesNotExist):145 result_repr = EMPTY_CHANGELIST_VALUE146 else:147 # Strip HTML tags in the resulting text, except if the148 # function has an "allow_tags" attribute set to True.149 if not allow_tags:150 result_repr = escape(result_repr)151 else:152 field_val = getattr(result, f.attname)153 154 if isinstance(f.rel, models.ManyToOneRel):155 if field_val is not None:156 result_repr = escape(getattr(result, f.name))157 else:158 result_repr = EMPTY_CHANGELIST_VALUE159 # Dates and times are special: They're formatted in a certain way.160 elif isinstance(f, models.DateField) or isinstance(f, models.TimeField):161 if field_val:162 (date_format, datetime_format, time_format) = get_date_formats()163 if isinstance(f, models.DateTimeField):164 result_repr = capfirst(dateformat.format(field_val, datetime_format))165 elif isinstance(f, models.TimeField):166 result_repr = capfirst(dateformat.time_format(field_val, time_format))167 else:168 result_repr = capfirst(dateformat.format(field_val, date_format))169 else:170 result_repr = EMPTY_CHANGELIST_VALUE171 row_class = ' class="nowrap"'172 # Booleans are special: We use images.173 elif isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField):174 result_repr = _boolean_icon(field_val)175 # DecimalFields are special: Zero-pad the decimals.176 elif isinstance(f, models.DecimalField):177 if field_val is not None:178 result_repr = ('%%.%sf' % f.decimal_places) % field_val179 else:180 result_repr = EMPTY_CHANGELIST_VALUE181 # Fields with choices are special: Use the representation182 # of the choice.183 elif f.choices:184 result_repr = dict(f.choices).get(field_val, EMPTY_CHANGELIST_VALUE)185 else:186 result_repr = escape(field_val)187 if force_unicode(result_repr) == '':188 result_repr = mark_safe(' ')189 # If list_display_links not defined, add the link tag to the first field190 if (first and not cl.list_display_links) or field_name in cl.list_display_links:191 table_tag = {True:'th', False:'td'}[first]192 first = False193 url = cl.url_for_result(result)194 # Convert the pk to something that can be used in Javascript.195 # Problem cases are long ints (23L) and non-ASCII strings.196 result_id = repr(force_unicode(getattr(result, pk)))[1:]197 yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % \198 (table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag))199 else:200 yield mark_safe(u'<td%s>%s</td>' % (row_class, conditional_escape(result_repr)))201 202 def results(cl):203 for res in cl.result_list:204 yield list(items_for_result(cl,res))205 206 def result_list(cl):207 return {'cl': cl,208 'result_headers': list(result_headers(cl)),209 'results': list(results(cl))}210 result_list = register.inclusion_tag("admin/change_list_results.html")(result_list)211 70 212 71 def date_hierarchy(cl): 213 72 if cl.date_hierarchy: -
django/contrib/admin/views/main.py
diff -r 76df9804bd63 -r 577c34da6045 django/contrib/admin/views/main.py
a b from django.contrib.admin.filterspecs im 2 2 from django.contrib.admin.filterspecs import FilterSpec 3 3 from django.contrib.admin.options import IncorrectLookupParameters 4 4 from django.contrib.admin.views.decorators import staff_member_required 5 from django.core.exceptions import ObjectDoesNotExist 6 from django.utils.html import escape, conditional_escape 7 from django.utils.text import capfirst 8 from django.utils import dateformat 5 9 from django.views.decorators.cache import never_cache 6 10 from django.core.paginator import ObjectPaginator, InvalidPage 7 11 from django.shortcuts import render_to_response 8 12 from django.db import models 9 13 from django.db.models.query import handle_legacy_orderlist, QuerySet 10 14 from django.http import Http404 11 from django.utils.encoding import force_unicode, smart_str 15 from django.utils.encoding import force_unicode, smart_str, smart_unicode 12 16 from django.utils.translation import ugettext 13 17 from django.utils.safestring import mark_safe 14 18 import operator … … class ChangeList(object): 342 346 343 347 def url_for_result(self, result): 344 348 return "%s/" % quote(getattr(result, self.pk_attname)) 349 350 def result_headers(self): 351 lookup_opts = self.lookup_opts 352 353 for i, field_name in enumerate(self.list_display): 354 try: 355 f = lookup_opts.get_field(field_name) 356 admin_order_field = None 357 except models.FieldDoesNotExist: 358 # For non-field list_display values, check for the function 359 # attribute "short_description". If that doesn't exist, fall back 360 # to the method name. And __str__ and __unicode__ are special-cases. 361 if field_name == '__unicode__': 362 header = force_unicode(lookup_opts.verbose_name) 363 elif field_name == '__str__': 364 header = smart_str(lookup_opts.verbose_name) 365 else: 366 attr = getattr(self.model, field_name) # Let AttributeErrors propagate. 367 try: 368 header = attr.short_description 369 except AttributeError: 370 header = field_name.replace('_', ' ') 371 372 # It is a non-field, but perhaps one that is sortable 373 admin_order_field = getattr(getattr(self.model, field_name), "admin_order_field", None) 374 if not admin_order_field: 375 yield {"text": header} 376 continue 377 378 # So this _is_ a sortable non-field. Go to the yield 379 # after the else clause. 380 else: 381 if isinstance(f.rel, models.ManyToOneRel) and f.null: 382 yield {"text": f.verbose_name} 383 continue 384 else: 385 header = f.verbose_name 386 387 th_classes = [] 388 new_order_type = 'asc' 389 if field_name == self.order_field or admin_order_field == self.order_field: 390 th_classes.append('sorted %sending' % self.order_type.lower()) 391 new_order_type = {'asc': 'desc', 'desc': 'asc'}[self.order_type.lower()] 392 393 yield {"text": header, 394 "sortable": True, 395 "url": self.get_query_string({ORDER_VAR: i, ORDER_TYPE_VAR: new_order_type}), 396 "class_attrib": mark_safe(th_classes and ' class="%s"' % ' '.join(th_classes) or '')} 397 398 def items_for_result(self, result): 399 first = True 400 pk = self.lookup_opts.pk.attname 401 for field_name in self.list_display: 402 row_class = '' 403 try: 404 f = self.lookup_opts.get_field(field_name) 405 except models.FieldDoesNotExist: 406 # For non-field list_display values, the value is either a method 407 # or a property. 408 try: 409 attr = getattr(result, field_name) 410 allow_tags = getattr(attr, 'allow_tags', False) 411 boolean = getattr(attr, 'boolean', False) 412 if callable(attr): 413 attr = attr() 414 if boolean: 415 allow_tags = True 416 result_repr = _boolean_icon(attr) 417 else: 418 result_repr = smart_unicode(attr) 419 except (AttributeError, ObjectDoesNotExist): 420 result_repr = EMPTY_CHANGELIST_VALUE 421 else: 422 # Strip HTML tags in the resulting text, except if the 423 # function has an "allow_tags" attribute set to True. 424 if not allow_tags: 425 result_repr = escape(result_repr) 426 else: 427 field_val = getattr(result, f.attname) 428 429 if isinstance(f.rel, models.ManyToOneRel): 430 if field_val is not None: 431 result_repr = escape(getattr(result, f.name)) 432 else: 433 result_repr = EMPTY_CHANGELIST_VALUE 434 # Dates and times are special: They're formatted in a certain way. 435 elif isinstance(f, models.DateField) or isinstance(f, models.TimeField): 436 if field_val: 437 (date_format, datetime_format, time_format) = get_date_formats() 438 if isinstance(f, models.DateTimeField): 439 result_repr = capfirst(dateformat.format(field_val, datetime_format)) 440 elif isinstance(f, models.TimeField): 441 result_repr = capfirst(dateformat.time_format(field_val, time_format)) 442 else: 443 result_repr = capfirst(dateformat.format(field_val, date_format)) 444 else: 445 result_repr = EMPTY_CHANGELIST_VALUE 446 row_class = ' class="nowrap"' 447 # Booleans are special: We use images. 448 elif isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField): 449 result_repr = _boolean_icon(field_val) 450 # DecimalFields are special: Zero-pad the decimals. 451 elif isinstance(f, models.DecimalField): 452 if field_val is not None: 453 result_repr = ('%%.%sf' % f.decimal_places) % field_val 454 else: 455 result_repr = EMPTY_CHANGELIST_VALUE 456 # Fields with choices are special: Use the representation 457 # of the choice. 458 elif f.choices: 459 result_repr = dict(f.choices).get(field_val, EMPTY_CHANGELIST_VALUE) 460 else: 461 result_repr = escape(field_val) 462 if force_unicode(result_repr) == '': 463 result_repr = mark_safe(' ') 464 # If list_display_links not defined, add the link tag to the first field 465 if (first and not self.list_display_links) or field_name in self.list_display_links: 466 table_tag = {True:'th', False:'td'}[first] 467 first = False 468 url = self.url_for_result(result) 469 # Convert the pk to something that can be used in Javascript. 470 # Problem cases are long ints (23L) and non-ASCII strings. 471 result_id = repr(force_unicode(getattr(result, pk)))[1:] 472 yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % \ 473 (table_tag, row_class, url, (self.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag)) 474 else: 475 yield mark_safe(u'<td%s>%s</td>' % (row_class, conditional_escape(result_repr))) 476 477 def results(self): 478 for res in self.result_list: 479 yield list(self.items_for_result(res)) 480