Fixed #2433 -- Added allow_future option to date-based generic views

git-svn-id: http://code.djangoproject.com/svn/django/trunk@3457 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2006-07-27 16:36:02 +00:00
parent c37a6fa17a
commit ecdd6ae6de
2 changed files with 80 additions and 25 deletions

View File

@ -7,7 +7,7 @@ import datetime, time
def archive_index(request, queryset, date_field, num_latest=15, def archive_index(request, queryset, date_field, num_latest=15,
template_name=None, template_loader=loader, template_name=None, template_loader=loader,
extra_context=None, allow_empty=False, context_processors=None, extra_context=None, allow_empty=False, context_processors=None,
mimetype=None): mimetype=None, allow_future=False):
""" """
Generic top-level archive of date-based objects. Generic top-level archive of date-based objects.
@ -20,6 +20,7 @@ def archive_index(request, queryset, date_field, num_latest=15,
""" """
if extra_context is None: extra_context = {} if extra_context is None: extra_context = {}
model = queryset.model model = queryset.model
if not allow_future:
queryset = queryset.filter(**{'%s__lte' % date_field: datetime.datetime.now()}) queryset = queryset.filter(**{'%s__lte' % date_field: datetime.datetime.now()})
date_list = queryset.dates(date_field, 'year')[::-1] date_list = queryset.dates(date_field, 'year')[::-1]
if not date_list and not allow_empty: if not date_list and not allow_empty:
@ -47,7 +48,7 @@ def archive_index(request, queryset, date_field, num_latest=15,
def archive_year(request, year, queryset, date_field, template_name=None, def archive_year(request, year, queryset, date_field, template_name=None,
template_loader=loader, extra_context=None, allow_empty=False, template_loader=loader, extra_context=None, allow_empty=False,
context_processors=None, template_object_name='object', mimetype=None, context_processors=None, template_object_name='object', mimetype=None,
make_object_list=False): make_object_list=False, allow_future=False):
""" """
Generic yearly archive view. Generic yearly archive view.
@ -67,8 +68,8 @@ def archive_year(request, year, queryset, date_field, template_name=None,
lookup_kwargs = {'%s__year' % date_field: year} lookup_kwargs = {'%s__year' % date_field: year}
# Only bother to check current date if the year isn't in the past. # Only bother to check current date if the year isn't in the past and future objects aren't requested.
if int(year) >= now.year: if int(year) >= now.year and not allow_future:
lookup_kwargs['%s__lte' % date_field] = now lookup_kwargs['%s__lte' % date_field] = now
date_list = queryset.filter(**lookup_kwargs).dates(date_field, 'month') date_list = queryset.filter(**lookup_kwargs).dates(date_field, 'month')
if not date_list and not allow_empty: if not date_list and not allow_empty:
@ -95,7 +96,7 @@ def archive_year(request, year, queryset, date_field, template_name=None,
def archive_month(request, year, month, queryset, date_field, def archive_month(request, year, month, queryset, date_field,
month_format='%b', template_name=None, template_loader=loader, month_format='%b', template_name=None, template_loader=loader,
extra_context=None, allow_empty=False, context_processors=None, extra_context=None, allow_empty=False, context_processors=None,
template_object_name='object', mimetype=None): template_object_name='object', mimetype=None, allow_future=False):
""" """
Generic monthly archive view. Generic monthly archive view.
@ -127,19 +128,28 @@ def archive_month(request, year, month, queryset, date_field,
last_day = first_day.replace(month=first_day.month + 1) last_day = first_day.replace(month=first_day.month + 1)
lookup_kwargs = {'%s__range' % date_field: (first_day, last_day)} lookup_kwargs = {'%s__range' % date_field: (first_day, last_day)}
# Only bother to check current date if the month isn't in the past. # Only bother to check current date if the month isn't in the past and future objects are requested.
if last_day >= now.date(): if last_day >= now.date() and not allow_future:
lookup_kwargs['%s__lte' % date_field] = now lookup_kwargs['%s__lte' % date_field] = now
object_list = queryset.filter(**lookup_kwargs) object_list = queryset.filter(**lookup_kwargs)
if not object_list and not allow_empty: if not object_list and not allow_empty:
raise Http404 raise Http404
# Calculate the next month, if applicable.
if allow_future:
next_month = last_day + datetime.timedelta(days=1)
elif last_day < datetime.date.today():
next_month = last_day + datetime.timedelta(days=1)
else:
next_month = None
if not template_name: if not template_name:
template_name = "%s/%s_archive_month.html" % (model._meta.app_label, model._meta.object_name.lower()) template_name = "%s/%s_archive_month.html" % (model._meta.app_label, model._meta.object_name.lower())
t = template_loader.get_template(template_name) t = template_loader.get_template(template_name)
c = RequestContext(request, { c = RequestContext(request, {
'%s_list' % template_object_name: object_list, '%s_list' % template_object_name: object_list,
'month': date, 'month': date,
'next_month': (last_day < datetime.date.today()) and (last_day + datetime.timedelta(days=1)) or None, 'next_month': next_month,
'previous_month': first_day - datetime.timedelta(days=1), 'previous_month': first_day - datetime.timedelta(days=1),
}, context_processors) }, context_processors)
for key, value in extra_context.items(): for key, value in extra_context.items():
@ -152,7 +162,7 @@ def archive_month(request, year, month, queryset, date_field,
def archive_week(request, year, week, queryset, date_field, def archive_week(request, year, week, queryset, date_field,
template_name=None, template_loader=loader, template_name=None, template_loader=loader,
extra_context=None, allow_empty=True, context_processors=None, extra_context=None, allow_empty=True, context_processors=None,
template_object_name='object', mimetype=None): template_object_name='object', mimetype=None, allow_future=False):
""" """
Generic weekly archive view. Generic weekly archive view.
@ -177,8 +187,8 @@ def archive_week(request, year, week, queryset, date_field,
last_day = date + datetime.timedelta(days=7) last_day = date + datetime.timedelta(days=7)
lookup_kwargs = {'%s__range' % date_field: (first_day, last_day)} lookup_kwargs = {'%s__range' % date_field: (first_day, last_day)}
# Only bother to check current date if the week isn't in the past. # Only bother to check current date if the week isn't in the past and future objects aren't requested.
if last_day >= now.date(): if last_day >= now.date() and not allow_future:
lookup_kwargs['%s__lte' % date_field] = now lookup_kwargs['%s__lte' % date_field] = now
object_list = queryset.filter(**lookup_kwargs) object_list = queryset.filter(**lookup_kwargs)
if not object_list and not allow_empty: if not object_list and not allow_empty:
@ -201,7 +211,7 @@ def archive_day(request, year, month, day, queryset, date_field,
month_format='%b', day_format='%d', template_name=None, month_format='%b', day_format='%d', template_name=None,
template_loader=loader, extra_context=None, allow_empty=False, template_loader=loader, extra_context=None, allow_empty=False,
context_processors=None, template_object_name='object', context_processors=None, template_object_name='object',
mimetype=None): mimetype=None, allow_future=False):
""" """
Generic daily archive view. Generic daily archive view.
@ -229,12 +239,21 @@ def archive_day(request, year, month, day, queryset, date_field,
'%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max)), '%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max)),
} }
# Only bother to check current date if the date isn't in the past. # Only bother to check current date if the date isn't in the past and future objects aren't requested.
if date >= now.date(): if date >= now.date() and not allow_future:
lookup_kwargs['%s__lte' % date_field] = now lookup_kwargs['%s__lte' % date_field] = now
object_list = queryset.filter(**lookup_kwargs) object_list = queryset.filter(**lookup_kwargs)
if not allow_empty and not object_list: if not allow_empty and not object_list:
raise Http404 raise Http404
# Calculate the next day, if applicable.
if allow_future:
next_day = date + datetime.timedelta(days=1)
elif date < datetime.date.today():
next_day = date + datetime.timedelta(days=1)
else:
next_day = None
if not template_name: if not template_name:
template_name = "%s/%s_archive_day.html" % (model._meta.app_label, model._meta.object_name.lower()) template_name = "%s/%s_archive_day.html" % (model._meta.app_label, model._meta.object_name.lower())
t = template_loader.get_template(template_name) t = template_loader.get_template(template_name)
@ -242,7 +261,7 @@ def archive_day(request, year, month, day, queryset, date_field,
'%s_list' % template_object_name: object_list, '%s_list' % template_object_name: object_list,
'day': date, 'day': date,
'previous_day': date - datetime.timedelta(days=1), 'previous_day': date - datetime.timedelta(days=1),
'next_day': (date < datetime.date.today()) and (date + datetime.timedelta(days=1)) or None, 'next_day': next_day,
}, context_processors) }, context_processors)
for key, value in extra_context.items(): for key, value in extra_context.items():
if callable(value): if callable(value):
@ -267,7 +286,7 @@ def object_detail(request, year, month, day, queryset, date_field,
month_format='%b', day_format='%d', object_id=None, slug=None, month_format='%b', day_format='%d', object_id=None, slug=None,
slug_field=None, template_name=None, template_name_field=None, slug_field=None, template_name=None, template_name_field=None,
template_loader=loader, extra_context=None, context_processors=None, template_loader=loader, extra_context=None, context_processors=None,
template_object_name='object', mimetype=None): template_object_name='object', mimetype=None, allow_future=False):
""" """
Generic detail view from year/month/day/slug or year/month/day/id structure. Generic detail view from year/month/day/slug or year/month/day/id structure.
@ -289,8 +308,8 @@ def object_detail(request, year, month, day, queryset, date_field,
'%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max)), '%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max)),
} }
# Only bother to check current date if the date isn't in the past. # Only bother to check current date if the date isn't in the past and future objects aren't requested.
if date >= now.date(): if date >= now.date() and not allow_future:
lookup_kwargs['%s__lte' % date_field] = now lookup_kwargs['%s__lte' % date_field] = now
if object_id: if object_id:
lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id

View File

@ -148,7 +148,8 @@ are views for displaying drilldown pages for date-based data.
**Description:** **Description:**
A top-level index page showing the "latest" objects, by date. Objects with A top-level index page showing the "latest" objects, by date. Objects with
a date in the *future* are not included. a date in the *future* are not included unless you set ``allow_future`` to
``True``.
**Required arguments:** **Required arguments:**
@ -185,6 +186,11 @@ a date in the *future* are not included.
* ``mimetype``: The MIME type to use for the resulting document. Defaults * ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting. to the value of the ``DEFAULT_MIME_TYPE`` setting.
* ``allow_future``: A boolean specifying whether to include "future"
objects on this page, where "future" means objects in which the field
specified in ``date_field`` is greater than the current date/time. By
default, this is ``False``.
**Template name:** **Template name:**
If ``template_name`` isn't specified, this view will use the template If ``template_name`` isn't specified, this view will use the template
@ -217,7 +223,8 @@ In addition to ``extra_context``, the template's context will be:
**Description:** **Description:**
A yearly archive page showing all available months in a given year. Objects A yearly archive page showing all available months in a given year. Objects
with a date in the *future* are not displayed. with a date in the *future* are not displayed unless you set ``allow_future``
to ``True``.
**Required arguments:** **Required arguments:**
@ -265,6 +272,11 @@ with a date in the *future* are not displayed.
* ``mimetype``: The MIME type to use for the resulting document. Defaults * ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting. to the value of the ``DEFAULT_MIME_TYPE`` setting.
* ``allow_future``: A boolean specifying whether to include "future"
objects on this page, where "future" means objects in which the field
specified in ``date_field`` is greater than the current date/time. By
default, this is ``False``.
**Template name:** **Template name:**
If ``template_name`` isn't specified, this view will use the template If ``template_name`` isn't specified, this view will use the template
@ -296,7 +308,8 @@ In addition to ``extra_context``, the template's context will be:
**Description:** **Description:**
A monthly archive page showing all objects in a given month. Objects with a A monthly archive page showing all objects in a given month. Objects with a
date in the *future* are not displayed. date in the *future* are not displayed unless you set ``allow_future`` to
``True``.
**Required arguments:** **Required arguments:**
@ -346,6 +359,11 @@ date in the *future* are not displayed.
* ``mimetype``: The MIME type to use for the resulting document. Defaults * ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting. to the value of the ``DEFAULT_MIME_TYPE`` setting.
* ``allow_future``: A boolean specifying whether to include "future"
objects on this page, where "future" means objects in which the field
specified in ``date_field`` is greater than the current date/time. By
default, this is ``False``.
**Template name:** **Template name:**
If ``template_name`` isn't specified, this view will use the template If ``template_name`` isn't specified, this view will use the template
@ -378,7 +396,7 @@ In addition to ``extra_context``, the template's context will be:
**Description:** **Description:**
A weekly archive page showing all objects in a given week. Objects with a date A weekly archive page showing all objects in a given week. Objects with a date
in the *future* are not displayed. in the *future* are not displayed unless you set ``allow_future`` to ``True``.
**Required arguments:** **Required arguments:**
@ -422,6 +440,11 @@ in the *future* are not displayed.
* ``mimetype``: The MIME type to use for the resulting document. Defaults * ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting. to the value of the ``DEFAULT_MIME_TYPE`` setting.
* ``allow_future``: A boolean specifying whether to include "future"
objects on this page, where "future" means objects in which the field
specified in ``date_field`` is greater than the current date/time. By
default, this is ``False``.
**Template name:** **Template name:**
If ``template_name`` isn't specified, this view will use the template If ``template_name`` isn't specified, this view will use the template
@ -445,7 +468,8 @@ In addition to ``extra_context``, the template's context will be:
**Description:** **Description:**
A day archive page showing all objects in a given day. Days in the future throw A day archive page showing all objects in a given day. Days in the future throw
a 404 error, regardless of whether any objects exist for future days. a 404 error, regardless of whether any objects exist for future days, unless
you set ``allow_future`` to ``True``.
**Required arguments:** **Required arguments:**
@ -501,6 +525,11 @@ a 404 error, regardless of whether any objects exist for future days.
* ``mimetype``: The MIME type to use for the resulting document. Defaults * ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting. to the value of the ``DEFAULT_MIME_TYPE`` setting.
* ``allow_future``: A boolean specifying whether to include "future"
objects on this page, where "future" means objects in which the field
specified in ``date_field`` is greater than the current date/time. By
default, this is ``False``.
**Template name:** **Template name:**
If ``template_name`` isn't specified, this view will use the template If ``template_name`` isn't specified, this view will use the template
@ -537,7 +566,9 @@ and today's date is used instead.
**Description:** **Description:**
A page representing an individual object. A page representing an individual object. If the object has a date value in the
future, the view will throw a 404 error by default, unless you set
``allow_future`` to ``True``.
**Required arguments:** **Required arguments:**
@ -604,6 +635,11 @@ A page representing an individual object.
* ``mimetype``: The MIME type to use for the resulting document. Defaults * ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_MIME_TYPE`` setting. to the value of the ``DEFAULT_MIME_TYPE`` setting.
* ``allow_future``: A boolean specifying whether to include "future"
objects on this page, where "future" means objects in which the field
specified in ``date_field`` is greater than the current date/time. By
default, this is ``False``.
**Template name:** **Template name:**
If ``template_name`` isn't specified, this view will use the template If ``template_name`` isn't specified, this view will use the template