Fixed #17830 -- Modified list_filter on DateTimeFields to account for the new time zone support. Thanks Glenn Washburn for the report and Jannis Leidel for the review.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17670 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Aymeric Augustin 2012-03-05 12:27:19 +00:00
parent f95141abcc
commit bf0abe0ea6
2 changed files with 53 additions and 40 deletions

View File

@ -11,6 +11,7 @@ from django.db import models
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.utils.encoding import smart_unicode from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from django.contrib.admin.util import (get_model_from_relation, from django.contrib.admin.util import (get_model_from_relation,
reverse_field_path, get_limit_choices_to_from_path, prepare_lookup_value) reverse_field_path, get_limit_choices_to_from_path, prepare_lookup_value)
@ -282,44 +283,49 @@ class DateFieldListFilter(FieldListFilter):
self.field_generic = '%s__' % field_path self.field_generic = '%s__' % field_path
self.date_params = dict([(k, v) for k, v in params.items() self.date_params = dict([(k, v) for k, v in params.items()
if k.startswith(self.field_generic)]) if k.startswith(self.field_generic)])
today = datetime.date.today()
one_week_ago = today - datetime.timedelta(days=7) now = timezone.now()
today_str = str(today) # When time zone support is enabled, convert "now" to the user's time
# zone so Django's definition of "Today" matches what the user expects.
if now.tzinfo is not None:
current_tz = timezone.get_current_timezone()
now = now.astimezone(current_tz)
if hasattr(current_tz, 'normalize'):
# available for pytz time zones
now = current_tz.normalize(now)
if isinstance(field, models.DateTimeField): if isinstance(field, models.DateTimeField):
today_str += ' 23:59:59' today = now.replace(hour=0, minute=0, second=0, microsecond=0)
self.lookup_kwarg_year = '%s__year' % field_path else: # field is a models.DateField
self.lookup_kwarg_month = '%s__month' % field_path today = now.date()
self.lookup_kwarg_day = '%s__day' % field_path tomorrow = today + datetime.timedelta(days=1)
self.lookup_kwarg_past_7_days_gte = '%s__gte' % field_path
self.lookup_kwarg_past_7_days_lte = '%s__lte' % field_path self.lookup_kwarg_since = '%s__gte' % field_path
self.lookup_kwarg_until = '%s__lt' % field_path
self.links = ( self.links = (
(_('Any date'), {}), (_('Any date'), {}),
(_('Today'), { (_('Today'), {
self.lookup_kwarg_year: str(today.year), self.lookup_kwarg_since: str(today),
self.lookup_kwarg_month: str(today.month), self.lookup_kwarg_until: str(tomorrow),
self.lookup_kwarg_day: str(today.day),
}), }),
(_('Past 7 days'), { (_('Past 7 days'), {
self.lookup_kwarg_past_7_days_gte: str(one_week_ago), self.lookup_kwarg_since: str(today - datetime.timedelta(days=7)),
self.lookup_kwarg_past_7_days_lte: today_str, self.lookup_kwarg_until: str(tomorrow),
}), }),
(_('This month'), { (_('This month'), {
self.lookup_kwarg_year: str(today.year), self.lookup_kwarg_since: str(today.replace(day=1)),
self.lookup_kwarg_month: str(today.month), self.lookup_kwarg_until: str(tomorrow),
}), }),
(_('This year'), { (_('This year'), {
self.lookup_kwarg_year: str(today.year), self.lookup_kwarg_since: str(today.replace(month=1, day=1)),
self.lookup_kwarg_until: str(tomorrow),
}), }),
) )
super(DateFieldListFilter, self).__init__( super(DateFieldListFilter, self).__init__(
field, request, params, model, model_admin, field_path) field, request, params, model, model_admin, field_path)
def expected_parameters(self): def expected_parameters(self):
return [ return [self.lookup_kwarg_since, self.lookup_kwarg_until]
self.lookup_kwarg_year, self.lookup_kwarg_month,
self.lookup_kwarg_day, self.lookup_kwarg_past_7_days_gte,
self.lookup_kwarg_past_7_days_lte
]
def choices(self, cl): def choices(self, cl):
for title, param_dict in self.links: for title, param_dict in self.links:

View File

@ -10,6 +10,7 @@ from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase, RequestFactory from django.test import TestCase, RequestFactory
from django.test.utils import override_settings
from django.utils.encoding import force_unicode from django.utils.encoding import force_unicode
from .models import Book from .models import Book
@ -115,6 +116,7 @@ class ListFiltersTests(TestCase):
def setUp(self): def setUp(self):
self.today = datetime.date.today() self.today = datetime.date.today()
self.tomorrow = self.today + datetime.timedelta(days=1)
self.one_week_ago = self.today - datetime.timedelta(days=7) self.one_week_ago = self.today - datetime.timedelta(days=7)
self.request_factory = RequestFactory() self.request_factory = RequestFactory()
@ -143,9 +145,8 @@ class ListFiltersTests(TestCase):
request = self.request_factory.get('/') request = self.request_factory.get('/')
changelist = self.get_changelist(request, Book, modeladmin) changelist = self.get_changelist(request, Book, modeladmin)
request = self.request_factory.get('/', {'date_registered__year': self.today.year, request = self.request_factory.get('/', {'date_registered__gte': self.today,
'date_registered__month': self.today.month, 'date_registered__lt': self.tomorrow})
'date_registered__day': self.today.day})
changelist = self.get_changelist(request, Book, modeladmin) changelist = self.get_changelist(request, Book, modeladmin)
# Make sure the correct queryset is returned # Make sure the correct queryset is returned
@ -157,13 +158,12 @@ class ListFiltersTests(TestCase):
self.assertEqual(force_unicode(filterspec.title), u'date registered') self.assertEqual(force_unicode(filterspec.title), u'date registered')
choice = select_by(filterspec.choices(changelist), "display", "Today") choice = select_by(filterspec.choices(changelist), "display", "Today")
self.assertEqual(choice['selected'], True) self.assertEqual(choice['selected'], True)
self.assertEqual(choice['query_string'], '?date_registered__day=%s' self.assertEqual(choice['query_string'], '?date_registered__gte=%s'
'&date_registered__month=%s' '&date_registered__lt=%s'
'&date_registered__year=%s' % (self.today, self.tomorrow))
% (self.today.day, self.today.month, self.today.year))
request = self.request_factory.get('/', {'date_registered__year': self.today.year, request = self.request_factory.get('/', {'date_registered__gte': self.today.replace(day=1),
'date_registered__month': self.today.month}) 'date_registered__lt': self.tomorrow})
changelist = self.get_changelist(request, Book, modeladmin) changelist = self.get_changelist(request, Book, modeladmin)
# Make sure the correct queryset is returned # Make sure the correct queryset is returned
@ -179,11 +179,12 @@ class ListFiltersTests(TestCase):
self.assertEqual(force_unicode(filterspec.title), u'date registered') self.assertEqual(force_unicode(filterspec.title), u'date registered')
choice = select_by(filterspec.choices(changelist), "display", "This month") choice = select_by(filterspec.choices(changelist), "display", "This month")
self.assertEqual(choice['selected'], True) self.assertEqual(choice['selected'], True)
self.assertEqual(choice['query_string'], '?date_registered__month=%s' self.assertEqual(choice['query_string'], '?date_registered__gte=%s'
'&date_registered__year=%s' '&date_registered__lt=%s'
% (self.today.month, self.today.year)) % (self.today.replace(day=1), self.tomorrow))
request = self.request_factory.get('/', {'date_registered__year': self.today.year}) request = self.request_factory.get('/', {'date_registered__gte': self.today.replace(month=1, day=1),
'date_registered__lt': self.tomorrow})
changelist = self.get_changelist(request, Book, modeladmin) changelist = self.get_changelist(request, Book, modeladmin)
# Make sure the correct queryset is returned # Make sure the correct queryset is returned
@ -199,11 +200,12 @@ class ListFiltersTests(TestCase):
self.assertEqual(force_unicode(filterspec.title), u'date registered') self.assertEqual(force_unicode(filterspec.title), u'date registered')
choice = select_by(filterspec.choices(changelist), "display", "This year") choice = select_by(filterspec.choices(changelist), "display", "This year")
self.assertEqual(choice['selected'], True) self.assertEqual(choice['selected'], True)
self.assertEqual(choice['query_string'], '?date_registered__year=%s' self.assertEqual(choice['query_string'], '?date_registered__gte=%s'
% (self.today.year)) '&date_registered__lt=%s'
% (self.today.replace(month=1, day=1), self.tomorrow))
request = self.request_factory.get('/', {'date_registered__gte': str(self.one_week_ago), request = self.request_factory.get('/', {'date_registered__gte': str(self.one_week_ago),
'date_registered__lte': str(self.today)}) 'date_registered__lt': str(self.tomorrow)})
changelist = self.get_changelist(request, Book, modeladmin) changelist = self.get_changelist(request, Book, modeladmin)
# Make sure the correct queryset is returned # Make sure the correct queryset is returned
@ -216,8 +218,13 @@ class ListFiltersTests(TestCase):
choice = select_by(filterspec.choices(changelist), "display", "Past 7 days") choice = select_by(filterspec.choices(changelist), "display", "Past 7 days")
self.assertEqual(choice['selected'], True) self.assertEqual(choice['selected'], True)
self.assertEqual(choice['query_string'], '?date_registered__gte=%s' self.assertEqual(choice['query_string'], '?date_registered__gte=%s'
'&date_registered__lte=%s' '&date_registered__lt=%s'
% (str(self.one_week_ago), str(self.today))) % (str(self.one_week_ago), str(self.tomorrow)))
@override_settings(USE_TZ=True)
def test_datefieldlistfilter_with_time_zone_support(self):
# Regression for #17830
self.test_datefieldlistfilter()
def test_allvaluesfieldlistfilter(self): def test_allvaluesfieldlistfilter(self):
modeladmin = BookAdmin(Book, site) modeladmin = BookAdmin(Book, site)