Ticket #6396: ticket_6396.patch

File ticket_6396.patch, 18.3 KB (added by korpios, 7 years ago)
  • django/contrib/admin/options.py

    diff -r 76df9804bd63 -r 577c34da6045 django/contrib/admin/options.py
    a b class ModelAdmin(BaseModelAdmin): 
    627627            'title': cl.title,
    628628            'is_popup': cl.is_popup,
    629629            'cl': cl,
     630            'result_headers': list(cl.result_headers()),
     631            'results': list(cl.results()),
    630632        })
    631633        c.update({'has_add_permission': self.has_add_permission(request)}),
    632634        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  
    3333{% endif %}
    3434{% endblock %}
    3535
    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
    3756{% block pagination %}{% pagination cl %}{% endblock %}
    3857</div>
    3958</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 
    11from django.conf import settings
    22from django.contrib.admin.views.main import ALL_VAR, EMPTY_CHANGELIST_VALUE
    33from django.contrib.admin.views.main import ORDER_VAR, ORDER_TYPE_VAR, PAGE_VAR, SEARCH_VAR
    4 from django.core.exceptions import ObjectDoesNotExist
    54from django.db import models
    65from django.utils import dateformat
    7 from django.utils.html import escape, conditional_escape
    8 from django.utils.text import capfirst
    96from django.utils.safestring import mark_safe
    107from django.utils.translation import get_date_formats, get_partial_date_formats, ugettext as _
    11 from django.utils.encoding import smart_unicode, smart_str, force_unicode
    128from django.template import Library
    139import datetime
    1410
    def pagination(cl): 
    6864    }
    6965pagination = register.inclusion_tag('admin/pagination.html')(pagination)
    7066
    71 def result_headers(cl):
    72     lookup_opts = cl.lookup_opts
    73 
    74     for i, field_name in enumerate(cl.list_display):
    75         try:
    76             f = lookup_opts.get_field(field_name)
    77             admin_order_field = None
    78         except models.FieldDoesNotExist:
    79             # For non-field list_display values, check for the function
    80             # attribute "short_description". If that doesn't exist, fall back
    81             # 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_description
    90                 except AttributeError:
    91                     header = field_name.replace('_', ' ')
    92 
    93             # It is a non-field, but perhaps one that is sortable
    94             admin_order_field = getattr(getattr(cl.model, field_name), "admin_order_field", None)
    95             if not admin_order_field:
    96                 yield {"text": header}
    97                 continue
    98 
    99             # So this _is_ a sortable non-field.  Go to the yield
    100             # after the else clause.
    101         else:
    102             if isinstance(f.rel, models.ManyToOneRel) and f.null:
    103                 yield {"text": f.verbose_name}
    104                 continue
    105             else:
    106                 header = f.verbose_name
    107 
    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 
    11967def _boolean_icon(field_val):
    12068    BOOLEAN_MAPPING = {True: 'yes', False: 'no', None: 'unknown'}
    12169    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 = True
    125     pk = cl.lookup_opts.pk.attname
    126     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 method
    132             # 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 = True
    141                     result_repr = _boolean_icon(attr)
    142                 else:
    143                     result_repr = smart_unicode(attr)
    144             except (AttributeError, ObjectDoesNotExist):
    145                 result_repr = EMPTY_CHANGELIST_VALUE
    146             else:
    147                 # Strip HTML tags in the resulting text, except if the
    148                 # 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_VALUE
    159             # 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_VALUE
    171                 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_val
    179                 else:
    180                     result_repr = EMPTY_CHANGELIST_VALUE
    181             # Fields with choices are special: Use the representation
    182             # 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('&nbsp;')
    189         # If list_display_links not defined, add the link tag to the first field
    190         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 = False
    193             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)
    21170
    21271def date_hierarchy(cl):
    21372    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 
    22from django.contrib.admin.filterspecs import FilterSpec
    33from django.contrib.admin.options import IncorrectLookupParameters
    44from django.contrib.admin.views.decorators import staff_member_required
     5from django.core.exceptions import ObjectDoesNotExist
     6from django.utils.html import escape, conditional_escape
     7from django.utils.text import capfirst
     8from django.utils import dateformat
    59from django.views.decorators.cache import never_cache
    610from django.core.paginator import ObjectPaginator, InvalidPage
    711from django.shortcuts import render_to_response
    812from django.db import models
    913from django.db.models.query import handle_legacy_orderlist, QuerySet
    1014from django.http import Http404
    11 from django.utils.encoding import force_unicode, smart_str
     15from django.utils.encoding import force_unicode, smart_str, smart_unicode
    1216from django.utils.translation import ugettext
    1317from django.utils.safestring import mark_safe
    1418import operator
    class ChangeList(object): 
    342346
    343347    def url_for_result(self, result):
    344348        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('&nbsp;')
     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
Back to Top