Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed #13196 -- Formatting in admin changelists.

Handled values returned by functions more like field values.
In particular, localized dates, times and datetimes properly,
and converted datetimes to the current timezone.
  • Loading branch information...
commit 905bd7fb44a0dbd0be0d455ab428c388714ae700 1 parent 7c27d15
@aaugustin aaugustin authored
View
13 django/contrib/admin/templatetags/admin_list.py
@@ -1,6 +1,7 @@
import datetime
-from django.contrib.admin.util import lookup_field, display_for_field, label_for_field
+from django.contrib.admin.util import (lookup_field, display_for_field,
+ display_for_value, label_for_field)
from django.contrib.admin.views.main import (ALL_VAR, EMPTY_CHANGELIST_VALUE,
ORDER_VAR, PAGE_VAR, SEARCH_VAR)
from django.contrib.admin.templatetags.admin_static import static
@@ -184,15 +185,15 @@ def items_for_result(cl, result, form):
boolean = getattr(attr, 'boolean', False)
if boolean:
allow_tags = True
- result_repr = _boolean_icon(value)
- else:
- result_repr = smart_unicode(value)
+ result_repr = display_for_value(value, boolean)
# Strip HTML tags in the resulting text, except if the
# function has an "allow_tags" attribute set to True.
if not allow_tags:
result_repr = escape(result_repr)
else:
result_repr = mark_safe(result_repr)
+ if isinstance(value, (datetime.date, datetime.time)):
+ row_class = ' class="nowrap"'
else:
if isinstance(f.rel, models.ManyToOneRel):
field_val = getattr(result, f.name)
@@ -202,9 +203,7 @@ def items_for_result(cl, result, form):
result_repr = escape(field_val)
else:
result_repr = display_for_field(value, f)
- if isinstance(f, models.DateField)\
- or isinstance(f, models.TimeField)\
- or isinstance(f, models.ForeignKey):
+ if isinstance(f, (models.DateField, models.TimeField, models.ForeignKey)):
row_class = ' class="nowrap"'
if force_unicode(result_repr) == '':
result_repr = mark_safe(' ')
View
23 django/contrib/admin/util.py
@@ -1,3 +1,6 @@
+import datetime
+import decimal
+
from django.db import models
from django.db.models.sql.constants import LOOKUP_SEP
from django.db.models.deletion import Collector
@@ -323,7 +326,7 @@ def display_for_field(value, field):
return EMPTY_CHANGELIST_VALUE
elif isinstance(field, models.DateTimeField):
return formats.localize(timezone.localtime(value))
- elif isinstance(field, models.DateField) or isinstance(field, models.TimeField):
+ elif isinstance(field, (models.DateField, models.TimeField)):
return formats.localize(value)
elif isinstance(field, models.DecimalField):
return formats.number_format(value, field.decimal_places)
@@ -333,6 +336,24 @@ def display_for_field(value, field):
return smart_unicode(value)
+def display_for_value(value, boolean=False):
+ from django.contrib.admin.templatetags.admin_list import _boolean_icon
+ from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE
+
+ if boolean:
+ return _boolean_icon(value)
+ elif value is None:
+ return EMPTY_CHANGELIST_VALUE
+ elif isinstance(value, datetime.datetime):
+ return formats.localize(timezone.localtime(value))
+ elif isinstance(value, (datetime.date, datetime.time)):
+ return formats.localize(value)
+ elif isinstance(value, (decimal.Decimal, float, int, long)):
+ return formats.number_format(value)
+ else:
+ return smart_unicode(value)
+
+
class NotRelationField(Exception):
pass
View
13 tests/regressiontests/admin_changelist/admin.py
@@ -3,8 +3,8 @@
from django.contrib import admin
from django.core.paginator import Paginator
-from .models import (Child, Parent, Genre, Band, Musician, Group, Quartet,
- Membership, ChordsMusician, ChordsBand, Invitation, Swallow)
+from .models import (Event, Child, Parent, Genre, Band, Musician, Group,
+ Quartet, Membership, ChordsMusician, ChordsBand, Invitation, Swallow)
site = admin.AdminSite(name="admin")
@@ -15,6 +15,15 @@ def __init__(self, queryset, page_size, orphans=0, allow_empty_first_page=True):
allow_empty_first_page=allow_empty_first_page)
+class EventAdmin(admin.ModelAdmin):
+ list_display = ['event_date_func']
+
+ def event_date_func(self, event):
+ return event.date
+
+site.register(Event, EventAdmin)
+
+
class ParentAdmin(admin.ModelAdmin):
list_filter = ['child__name']
search_fields = ['child__name']
View
2  tests/regressiontests/admin_changelist/models.py
@@ -1,5 +1,7 @@
from django.db import models
+class Event(models.Model):
+ date = models.DateField()
class Parent(models.Model):
name = models.CharField(max_length=128)
View
22 tests/regressiontests/admin_changelist/tests.py
@@ -1,5 +1,7 @@
from __future__ import absolute_import
+import datetime
+
from django.contrib import admin
from django.contrib.admin.options import IncorrectLookupParameters
from django.contrib.admin.views.main import ChangeList, SEARCH_VAR, ALL_VAR
@@ -7,14 +9,15 @@
from django.template import Context, Template
from django.test import TestCase
from django.test.client import RequestFactory
+from django.utils import formats
from .admin import (ChildAdmin, QuartetAdmin, BandAdmin, ChordsBandAdmin,
GroupAdmin, ParentAdmin, DynamicListDisplayChildAdmin,
DynamicListDisplayLinksChildAdmin, CustomPaginationAdmin,
FilteredChildAdmin, CustomPaginator, site as custom_site,
SwallowAdmin)
-from .models import (Child, Parent, Genre, Band, Musician, Group, Quartet,
- Membership, ChordsMusician, ChordsBand, Invitation, Swallow,
+from .models import (Event, Child, Parent, Genre, Band, Musician, Group,
+ Quartet, Membership, ChordsMusician, ChordsBand, Invitation, Swallow,
UnorderedObject, OrderedObject)
@@ -325,6 +328,19 @@ def test_pagination(self):
self.assertEqual(cl.paginator.count, 30)
self.assertEqual(cl.paginator.page_range, [1, 2, 3])
+ def test_computed_list_display_localization(self):
+ """
+ Regression test for #13196: output of functions should be localized
+ in the changelist.
+ """
+ User.objects.create_superuser(
+ username='super', email='super@localhost', password='secret')
+ self.client.login(username='super', password='secret')
+ event = Event.objects.create(date=datetime.date.today())
+ response = self.client.get('/admin/admin_changelist/event/')
+ self.assertContains(response, formats.localize(event.date))
+ self.assertNotContains(response, unicode(event.date))
+
def test_dynamic_list_display(self):
"""
Regression tests for #14206: dynamic list_display support.
@@ -519,4 +535,4 @@ def check_results_order(ascending=False):
OrderedObjectAdmin.ordering = ['-id', 'bool']
check_results_order()
OrderedObjectAdmin.ordering = ['id', 'bool']
- check_results_order(ascending=True)
+ check_results_order(ascending=True)
Please sign in to comment.
Something went wrong with that request. Please try again.