mirror of https://github.com/django/django.git
Fixed #13607 -- Auto-initialize admin's date hierarchy links intelligently. Thanks, Simon Meers.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@14879 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
88ff656731
commit
2c2209b473
|
@ -231,6 +231,16 @@ def date_hierarchy(cl):
|
||||||
|
|
||||||
link = lambda d: cl.get_query_string(d, [field_generic])
|
link = lambda d: cl.get_query_string(d, [field_generic])
|
||||||
|
|
||||||
|
if not (year_lookup or month_lookup or day_lookup):
|
||||||
|
# select appropriate start level
|
||||||
|
date_range = cl.query_set.aggregate(first=models.Min(field_name),
|
||||||
|
last=models.Max(field_name))
|
||||||
|
if date_range['first'] and date_range['last']:
|
||||||
|
if date_range['first'].year == date_range['last'].year:
|
||||||
|
year_lookup = date_range['first'].year
|
||||||
|
if date_range['first'].month == date_range['last'].month:
|
||||||
|
month_lookup = date_range['first'].month
|
||||||
|
|
||||||
if year_lookup and month_lookup and day_lookup:
|
if year_lookup and month_lookup and day_lookup:
|
||||||
day = datetime.date(int(year_lookup), int(month_lookup), int(day_lookup))
|
day = datetime.date(int(year_lookup), int(month_lookup), int(day_lookup))
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -107,6 +107,12 @@ subclass::
|
||||||
|
|
||||||
date_hierarchy = 'pub_date'
|
date_hierarchy = 'pub_date'
|
||||||
|
|
||||||
|
.. versionadded:: 1.3
|
||||||
|
|
||||||
|
This will intelligently populate itself based on available data,
|
||||||
|
e.g. if all the dates are in one month, it'll show the day-level
|
||||||
|
drill-down only.
|
||||||
|
|
||||||
.. attribute:: ModelAdmin.form
|
.. attribute:: ModelAdmin.form
|
||||||
|
|
||||||
By default a ``ModelForm`` is dynamically created for your model. It is
|
By default a ``ModelForm`` is dynamically created for your model. It is
|
||||||
|
|
|
@ -320,7 +320,7 @@ class Podcast(Media):
|
||||||
class PodcastAdmin(admin.ModelAdmin):
|
class PodcastAdmin(admin.ModelAdmin):
|
||||||
list_display = ('name', 'release_date')
|
list_display = ('name', 'release_date')
|
||||||
list_editable = ('release_date',)
|
list_editable = ('release_date',)
|
||||||
|
date_hierarchy = 'release_date'
|
||||||
ordering = ('name',)
|
ordering = ('name',)
|
||||||
|
|
||||||
class Vodcast(Media):
|
class Vodcast(Media):
|
||||||
|
|
|
@ -6,6 +6,7 @@ import datetime
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
from django.core.files import temp as tempfile
|
from django.core.files import temp as tempfile
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
# Register auth models with the admin.
|
# Register auth models with the admin.
|
||||||
from django.contrib.auth import REDIRECT_FIELD_NAME, admin
|
from django.contrib.auth import REDIRECT_FIELD_NAME, admin
|
||||||
from django.contrib.auth.models import User, Permission, UNUSABLE_PASSWORD
|
from django.contrib.auth.models import User, Permission, UNUSABLE_PASSWORD
|
||||||
|
@ -2395,3 +2396,105 @@ class ValidXHTMLTests(TestCase):
|
||||||
response = self.client.get('/test_admin/%s/admin_views/' % self.urlbit)
|
response = self.client.get('/test_admin/%s/admin_views/' % self.urlbit)
|
||||||
self.assertFalse(' lang=""' in response.content)
|
self.assertFalse(' lang=""' in response.content)
|
||||||
self.assertFalse(' xml:lang=""' in response.content)
|
self.assertFalse(' xml:lang=""' in response.content)
|
||||||
|
|
||||||
|
|
||||||
|
class DateHierarchyTests(TestCase):
|
||||||
|
fixtures = ['admin-views-users.xml']
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.client.login(username='super', password='secret')
|
||||||
|
|
||||||
|
def assert_contains_year_link(self, response, date):
|
||||||
|
self.assertContains(response, '?release_date__year=%d"' % (date.year,))
|
||||||
|
|
||||||
|
def assert_contains_month_link(self, response, date):
|
||||||
|
self.assertContains(
|
||||||
|
response, '?release_date__year=%d&release_date__month=%d"' % (
|
||||||
|
date.year, date.month))
|
||||||
|
|
||||||
|
def assert_contains_day_link(self, response, date):
|
||||||
|
self.assertContains(
|
||||||
|
response, '?release_date__year=%d&'
|
||||||
|
'release_date__month=%d&release_date__day=%d"' % (
|
||||||
|
date.year, date.month, date.day))
|
||||||
|
|
||||||
|
def test_empty(self):
|
||||||
|
"""
|
||||||
|
Ensure that no date hierarchy links display with empty changelist.
|
||||||
|
"""
|
||||||
|
response = self.client.get(
|
||||||
|
reverse('admin:admin_views_podcast_changelist'))
|
||||||
|
self.assertNotContains(response, 'release_date__year=')
|
||||||
|
self.assertNotContains(response, 'release_date__month=')
|
||||||
|
self.assertNotContains(response, 'release_date__day=')
|
||||||
|
|
||||||
|
def test_single(self):
|
||||||
|
"""
|
||||||
|
Ensure that single day-level date hierarchy appears for single object.
|
||||||
|
"""
|
||||||
|
DATE = datetime.date(2000, 6, 30)
|
||||||
|
Podcast.objects.create(release_date=DATE)
|
||||||
|
response = self.client.get(
|
||||||
|
reverse('admin:admin_views_podcast_changelist'))
|
||||||
|
self.assert_contains_day_link(response, DATE)
|
||||||
|
|
||||||
|
def test_within_month(self):
|
||||||
|
"""
|
||||||
|
Ensure that day-level links appear for changelist within single month.
|
||||||
|
"""
|
||||||
|
DATES = (datetime.date(2000, 6, 30),
|
||||||
|
datetime.date(2000, 6, 15),
|
||||||
|
datetime.date(2000, 6, 3))
|
||||||
|
for date in DATES:
|
||||||
|
Podcast.objects.create(release_date=date)
|
||||||
|
response = self.client.get(
|
||||||
|
reverse('admin:admin_views_podcast_changelist'))
|
||||||
|
for date in DATES:
|
||||||
|
self.assert_contains_day_link(response, date)
|
||||||
|
|
||||||
|
def test_within_year(self):
|
||||||
|
"""
|
||||||
|
Ensure that month-level links appear for changelist within single year.
|
||||||
|
"""
|
||||||
|
DATES = (datetime.date(2000, 1, 30),
|
||||||
|
datetime.date(2000, 3, 15),
|
||||||
|
datetime.date(2000, 5, 3))
|
||||||
|
for date in DATES:
|
||||||
|
Podcast.objects.create(release_date=date)
|
||||||
|
response = self.client.get(
|
||||||
|
reverse('admin:admin_views_podcast_changelist'))
|
||||||
|
# no day-level links
|
||||||
|
self.assertNotContains(response, 'release_date__day=')
|
||||||
|
for date in DATES:
|
||||||
|
self.assert_contains_month_link(response, date)
|
||||||
|
|
||||||
|
def test_multiple_years(self):
|
||||||
|
"""
|
||||||
|
Ensure that year-level links appear for year-spanning changelist.
|
||||||
|
"""
|
||||||
|
DATES = (datetime.date(2001, 1, 30),
|
||||||
|
datetime.date(2003, 3, 15),
|
||||||
|
datetime.date(2005, 5, 3))
|
||||||
|
for date in DATES:
|
||||||
|
Podcast.objects.create(release_date=date)
|
||||||
|
response = self.client.get(
|
||||||
|
reverse('admin:admin_views_podcast_changelist'))
|
||||||
|
# no day/month-level links
|
||||||
|
self.assertNotContains(response, 'release_date__day=')
|
||||||
|
self.assertNotContains(response, 'release_date__month=')
|
||||||
|
for date in DATES:
|
||||||
|
self.assert_contains_year_link(response, date)
|
||||||
|
|
||||||
|
# and make sure GET parameters still behave correctly
|
||||||
|
for date in DATES:
|
||||||
|
response = self.client.get(
|
||||||
|
'%s?release_date__year=%d' % (
|
||||||
|
reverse('admin:admin_views_podcast_changelist'),
|
||||||
|
date.year))
|
||||||
|
self.assert_contains_month_link(response, date)
|
||||||
|
|
||||||
|
response = self.client.get(
|
||||||
|
'%s?release_date__year=%d&release_date__month=%d' % (
|
||||||
|
reverse('admin:admin_views_podcast_changelist'),
|
||||||
|
date.year, date.month))
|
||||||
|
self.assert_contains_day_link(response, date)
|
||||||
|
|
Loading…
Reference in New Issue