app/django/views/generic/date_based.py
changeset 54 03e267d67478
child 323 ff1a9aa48cfd
equal deleted inserted replaced
53:57b4279d8c4e 54:03e267d67478
       
     1 import datetime
       
     2 import time
       
     3 
       
     4 from django.template import loader, RequestContext
       
     5 from django.core.exceptions import ObjectDoesNotExist
       
     6 from django.core.xheaders import populate_xheaders
       
     7 from django.db.models.fields import DateTimeField
       
     8 from django.http import Http404, HttpResponse
       
     9 
       
    10 def archive_index(request, queryset, date_field, num_latest=15,
       
    11         template_name=None, template_loader=loader,
       
    12         extra_context=None, allow_empty=True, context_processors=None,
       
    13         mimetype=None, allow_future=False, template_object_name='latest'):
       
    14     """
       
    15     Generic top-level archive of date-based objects.
       
    16 
       
    17     Templates: ``<app_label>/<model_name>_archive.html``
       
    18     Context:
       
    19         date_list
       
    20             List of years
       
    21         latest
       
    22             Latest N (defaults to 15) objects by date
       
    23     """
       
    24     if extra_context is None: extra_context = {}
       
    25     model = queryset.model
       
    26     if not allow_future:
       
    27         queryset = queryset.filter(**{'%s__lte' % date_field: datetime.datetime.now()})
       
    28     date_list = queryset.dates(date_field, 'year')[::-1]
       
    29     if not date_list and not allow_empty:
       
    30         raise Http404, "No %s available" % model._meta.verbose_name
       
    31 
       
    32     if date_list and num_latest:
       
    33         latest = queryset.order_by('-'+date_field)[:num_latest]
       
    34     else:
       
    35         latest = None
       
    36 
       
    37     if not template_name:
       
    38         template_name = "%s/%s_archive.html" % (model._meta.app_label, model._meta.object_name.lower())
       
    39     t = template_loader.get_template(template_name)
       
    40     c = RequestContext(request, {
       
    41         'date_list' : date_list,
       
    42         template_object_name : latest,
       
    43     }, context_processors)
       
    44     for key, value in extra_context.items():
       
    45         if callable(value):
       
    46             c[key] = value()
       
    47         else:
       
    48             c[key] = value
       
    49     return HttpResponse(t.render(c), mimetype=mimetype)
       
    50 
       
    51 def archive_year(request, year, queryset, date_field, template_name=None,
       
    52         template_loader=loader, extra_context=None, allow_empty=False,
       
    53         context_processors=None, template_object_name='object', mimetype=None,
       
    54         make_object_list=False, allow_future=False):
       
    55     """
       
    56     Generic yearly archive view.
       
    57 
       
    58     Templates: ``<app_label>/<model_name>_archive_year.html``
       
    59     Context:
       
    60         date_list
       
    61             List of months in this year with objects
       
    62         year
       
    63             This year
       
    64         object_list
       
    65             List of objects published in the given month
       
    66             (Only available if make_object_list argument is True)
       
    67     """
       
    68     if extra_context is None: extra_context = {}
       
    69     model = queryset.model
       
    70     now = datetime.datetime.now()
       
    71 
       
    72     lookup_kwargs = {'%s__year' % date_field: year}
       
    73 
       
    74     # Only bother to check current date if the year isn't in the past and future objects aren't requested.
       
    75     if int(year) >= now.year and not allow_future:
       
    76         lookup_kwargs['%s__lte' % date_field] = now
       
    77     date_list = queryset.filter(**lookup_kwargs).dates(date_field, 'month')
       
    78     if not date_list and not allow_empty:
       
    79         raise Http404
       
    80     if make_object_list:
       
    81         object_list = queryset.filter(**lookup_kwargs)
       
    82     else:
       
    83         object_list = []
       
    84     if not template_name:
       
    85         template_name = "%s/%s_archive_year.html" % (model._meta.app_label, model._meta.object_name.lower())
       
    86     t = template_loader.get_template(template_name)
       
    87     c = RequestContext(request, {
       
    88         'date_list': date_list,
       
    89         'year': year,
       
    90         '%s_list' % template_object_name: object_list,
       
    91     }, context_processors)
       
    92     for key, value in extra_context.items():
       
    93         if callable(value):
       
    94             c[key] = value()
       
    95         else:
       
    96             c[key] = value
       
    97     return HttpResponse(t.render(c), mimetype=mimetype)
       
    98 
       
    99 def archive_month(request, year, month, queryset, date_field,
       
   100         month_format='%b', template_name=None, template_loader=loader,
       
   101         extra_context=None, allow_empty=False, context_processors=None,
       
   102         template_object_name='object', mimetype=None, allow_future=False):
       
   103     """
       
   104     Generic monthly archive view.
       
   105 
       
   106     Templates: ``<app_label>/<model_name>_archive_month.html``
       
   107     Context:
       
   108         month:
       
   109             (date) this month
       
   110         next_month:
       
   111             (date) the first day of the next month, or None if the next month is in the future
       
   112         previous_month:
       
   113             (date) the first day of the previous month
       
   114         object_list:
       
   115             list of objects published in the given month
       
   116     """
       
   117     if extra_context is None: extra_context = {}
       
   118     try:
       
   119         date = datetime.date(*time.strptime(year+month, '%Y'+month_format)[:3])
       
   120     except ValueError:
       
   121         raise Http404
       
   122 
       
   123     model = queryset.model
       
   124     now = datetime.datetime.now()
       
   125 
       
   126     # Calculate first and last day of month, for use in a date-range lookup.
       
   127     first_day = date.replace(day=1)
       
   128     if first_day.month == 12:
       
   129         last_day = first_day.replace(year=first_day.year + 1, month=1)
       
   130     else:
       
   131         last_day = first_day.replace(month=first_day.month + 1)
       
   132     lookup_kwargs = {'%s__range' % date_field: (first_day, last_day)}
       
   133 
       
   134     # Only bother to check current date if the month isn't in the past and future objects are requested.
       
   135     if last_day >= now.date() and not allow_future:
       
   136         lookup_kwargs['%s__lte' % date_field] = now
       
   137     object_list = queryset.filter(**lookup_kwargs)
       
   138     if not object_list and not allow_empty:
       
   139         raise Http404
       
   140 
       
   141     # Calculate the next month, if applicable.
       
   142     if allow_future:
       
   143         next_month = last_day + datetime.timedelta(days=1)
       
   144     elif last_day < datetime.date.today():
       
   145         next_month = last_day + datetime.timedelta(days=1)
       
   146     else:
       
   147         next_month = None
       
   148 
       
   149     if not template_name:
       
   150         template_name = "%s/%s_archive_month.html" % (model._meta.app_label, model._meta.object_name.lower())
       
   151     t = template_loader.get_template(template_name)
       
   152     c = RequestContext(request, {
       
   153         '%s_list' % template_object_name: object_list,
       
   154         'month': date,
       
   155         'next_month': next_month,
       
   156         'previous_month': first_day - datetime.timedelta(days=1),
       
   157     }, context_processors)
       
   158     for key, value in extra_context.items():
       
   159         if callable(value):
       
   160             c[key] = value()
       
   161         else:
       
   162             c[key] = value
       
   163     return HttpResponse(t.render(c), mimetype=mimetype)
       
   164 
       
   165 def archive_week(request, year, week, queryset, date_field,
       
   166         template_name=None, template_loader=loader,
       
   167         extra_context=None, allow_empty=True, context_processors=None,
       
   168         template_object_name='object', mimetype=None, allow_future=False):
       
   169     """
       
   170     Generic weekly archive view.
       
   171 
       
   172     Templates: ``<app_label>/<model_name>_archive_week.html``
       
   173     Context:
       
   174         week:
       
   175             (date) this week
       
   176         object_list:
       
   177             list of objects published in the given week
       
   178     """
       
   179     if extra_context is None: extra_context = {}
       
   180     try:
       
   181         date = datetime.date(*time.strptime(year+'-0-'+week, '%Y-%w-%U')[:3])
       
   182     except ValueError:
       
   183         raise Http404
       
   184 
       
   185     model = queryset.model
       
   186     now = datetime.datetime.now()
       
   187 
       
   188     # Calculate first and last day of week, for use in a date-range lookup.
       
   189     first_day = date
       
   190     last_day = date + datetime.timedelta(days=7)
       
   191     lookup_kwargs = {'%s__range' % date_field: (first_day, last_day)}
       
   192 
       
   193     # Only bother to check current date if the week isn't in the past and future objects aren't requested.
       
   194     if last_day >= now.date() and not allow_future:
       
   195         lookup_kwargs['%s__lte' % date_field] = now
       
   196     object_list = queryset.filter(**lookup_kwargs)
       
   197     if not object_list and not allow_empty:
       
   198         raise Http404
       
   199     if not template_name:
       
   200         template_name = "%s/%s_archive_week.html" % (model._meta.app_label, model._meta.object_name.lower())
       
   201     t = template_loader.get_template(template_name)
       
   202     c = RequestContext(request, {
       
   203         '%s_list' % template_object_name: object_list,
       
   204         'week': date,
       
   205     })
       
   206     for key, value in extra_context.items():
       
   207         if callable(value):
       
   208             c[key] = value()
       
   209         else:
       
   210             c[key] = value
       
   211     return HttpResponse(t.render(c), mimetype=mimetype)
       
   212 
       
   213 def archive_day(request, year, month, day, queryset, date_field,
       
   214         month_format='%b', day_format='%d', template_name=None,
       
   215         template_loader=loader, extra_context=None, allow_empty=False,
       
   216         context_processors=None, template_object_name='object',
       
   217         mimetype=None, allow_future=False):
       
   218     """
       
   219     Generic daily archive view.
       
   220 
       
   221     Templates: ``<app_label>/<model_name>_archive_day.html``
       
   222     Context:
       
   223         object_list:
       
   224             list of objects published that day
       
   225         day:
       
   226             (datetime) the day
       
   227         previous_day
       
   228             (datetime) the previous day
       
   229         next_day
       
   230             (datetime) the next day, or None if the current day is today
       
   231     """
       
   232     if extra_context is None: extra_context = {}
       
   233     try:
       
   234         date = datetime.date(*time.strptime(year+month+day, '%Y'+month_format+day_format)[:3])
       
   235     except ValueError:
       
   236         raise Http404
       
   237 
       
   238     model = queryset.model
       
   239     now = datetime.datetime.now()
       
   240 
       
   241     if isinstance(model._meta.get_field(date_field), DateTimeField):
       
   242         lookup_kwargs = {'%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max))}
       
   243     else:
       
   244         lookup_kwargs = {date_field: date}
       
   245 
       
   246     # Only bother to check current date if the date isn't in the past and future objects aren't requested.
       
   247     if date >= now.date() and not allow_future:
       
   248         lookup_kwargs['%s__lte' % date_field] = now
       
   249     object_list = queryset.filter(**lookup_kwargs)
       
   250     if not allow_empty and not object_list:
       
   251         raise Http404
       
   252 
       
   253     # Calculate the next day, if applicable.
       
   254     if allow_future:
       
   255         next_day = date + datetime.timedelta(days=1)
       
   256     elif date < datetime.date.today():
       
   257         next_day = date + datetime.timedelta(days=1)
       
   258     else:
       
   259         next_day = None
       
   260 
       
   261     if not template_name:
       
   262         template_name = "%s/%s_archive_day.html" % (model._meta.app_label, model._meta.object_name.lower())
       
   263     t = template_loader.get_template(template_name)
       
   264     c = RequestContext(request, {
       
   265         '%s_list' % template_object_name: object_list,
       
   266         'day': date,
       
   267         'previous_day': date - datetime.timedelta(days=1),
       
   268         'next_day': next_day,
       
   269     }, context_processors)
       
   270     for key, value in extra_context.items():
       
   271         if callable(value):
       
   272             c[key] = value()
       
   273         else:
       
   274             c[key] = value
       
   275     return HttpResponse(t.render(c), mimetype=mimetype)
       
   276 
       
   277 def archive_today(request, **kwargs):
       
   278     """
       
   279     Generic daily archive view for today. Same as archive_day view.
       
   280     """
       
   281     today = datetime.date.today()
       
   282     kwargs.update({
       
   283         'year': str(today.year),
       
   284         'month': today.strftime('%b').lower(),
       
   285         'day': str(today.day),
       
   286     })
       
   287     return archive_day(request, **kwargs)
       
   288 
       
   289 def object_detail(request, year, month, day, queryset, date_field,
       
   290         month_format='%b', day_format='%d', object_id=None, slug=None,
       
   291         slug_field='slug', template_name=None, template_name_field=None,
       
   292         template_loader=loader, extra_context=None, context_processors=None,
       
   293         template_object_name='object', mimetype=None, allow_future=False):
       
   294     """
       
   295     Generic detail view from year/month/day/slug or year/month/day/id structure.
       
   296 
       
   297     Templates: ``<app_label>/<model_name>_detail.html``
       
   298     Context:
       
   299         object:
       
   300             the object to be detailed
       
   301     """
       
   302     if extra_context is None: extra_context = {}
       
   303     try:
       
   304         date = datetime.date(*time.strptime(year+month+day, '%Y'+month_format+day_format)[:3])
       
   305     except ValueError:
       
   306         raise Http404
       
   307 
       
   308     model = queryset.model
       
   309     now = datetime.datetime.now()
       
   310 
       
   311     if isinstance(model._meta.get_field(date_field), DateTimeField):
       
   312         lookup_kwargs = {'%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max))}
       
   313     else:
       
   314         lookup_kwargs = {date_field: date}
       
   315 
       
   316     # Only bother to check current date if the date isn't in the past and future objects aren't requested.
       
   317     if date >= now.date() and not allow_future:
       
   318         lookup_kwargs['%s__lte' % date_field] = now
       
   319     if object_id:
       
   320         lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id
       
   321     elif slug and slug_field:
       
   322         lookup_kwargs['%s__exact' % slug_field] = slug
       
   323     else:
       
   324         raise AttributeError, "Generic detail view must be called with either an object_id or a slug/slugfield"
       
   325     try:
       
   326         obj = queryset.get(**lookup_kwargs)
       
   327     except ObjectDoesNotExist:
       
   328         raise Http404, "No %s found for" % model._meta.verbose_name
       
   329     if not template_name:
       
   330         template_name = "%s/%s_detail.html" % (model._meta.app_label, model._meta.object_name.lower())
       
   331     if template_name_field:
       
   332         template_name_list = [getattr(obj, template_name_field), template_name]
       
   333         t = template_loader.select_template(template_name_list)
       
   334     else:
       
   335         t = template_loader.get_template(template_name)
       
   336     c = RequestContext(request, {
       
   337         template_object_name: obj,
       
   338     }, context_processors)
       
   339     for key, value in extra_context.items():
       
   340         if callable(value):
       
   341             c[key] = value()
       
   342         else:
       
   343             c[key] = value
       
   344     response = HttpResponse(t.render(c), mimetype=mimetype)
       
   345     populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name))
       
   346     return response