web/lib/django/views/generic/date_based.py
changeset 38 77b6da96e6f1
equal deleted inserted replaced
37:8d941af65caf 38:77b6da96e6f1
       
     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         date_list:
       
   109             List of days in this month with objects
       
   110         month:
       
   111             (date) this month
       
   112         next_month:
       
   113             (date) the first day of the next month, or None if the next month is in the future
       
   114         previous_month:
       
   115             (date) the first day of the previous month
       
   116         object_list:
       
   117             list of objects published in the given month
       
   118     """
       
   119     if extra_context is None: extra_context = {}
       
   120     try:
       
   121         tt = time.strptime("%s-%s" % (year, month), '%s-%s' % ('%Y', month_format))
       
   122         date = datetime.date(*tt[:3])
       
   123     except ValueError:
       
   124         raise Http404
       
   125 
       
   126     model = queryset.model
       
   127     now = datetime.datetime.now()
       
   128 
       
   129     # Calculate first and last day of month, for use in a date-range lookup.
       
   130     first_day = date.replace(day=1)
       
   131     if first_day.month == 12:
       
   132         last_day = first_day.replace(year=first_day.year + 1, month=1)
       
   133     else:
       
   134         last_day = first_day.replace(month=first_day.month + 1)
       
   135     lookup_kwargs = {
       
   136         '%s__gte' % date_field: first_day,
       
   137         '%s__lt' % date_field: last_day,
       
   138     }
       
   139 
       
   140     # Only bother to check current date if the month isn't in the past and future objects are requested.
       
   141     if last_day >= now.date() and not allow_future:
       
   142         lookup_kwargs['%s__lte' % date_field] = now
       
   143     object_list = queryset.filter(**lookup_kwargs)
       
   144     date_list = object_list.dates(date_field, 'day')
       
   145     if not object_list and not allow_empty:
       
   146         raise Http404
       
   147 
       
   148     # Calculate the next month, if applicable.
       
   149     if allow_future:
       
   150         next_month = last_day
       
   151     elif last_day <= datetime.date.today():
       
   152         next_month = last_day
       
   153     else:
       
   154         next_month = None
       
   155 
       
   156     # Calculate the previous month
       
   157     if first_day.month == 1:
       
   158         previous_month = first_day.replace(year=first_day.year-1,month=12)
       
   159     else:
       
   160         previous_month = first_day.replace(month=first_day.month-1)
       
   161 
       
   162     if not template_name:
       
   163         template_name = "%s/%s_archive_month.html" % (model._meta.app_label, model._meta.object_name.lower())
       
   164     t = template_loader.get_template(template_name)
       
   165     c = RequestContext(request, {
       
   166         'date_list': date_list,
       
   167         '%s_list' % template_object_name: object_list,
       
   168         'month': date,
       
   169         'next_month': next_month,
       
   170         'previous_month': previous_month,
       
   171     }, context_processors)
       
   172     for key, value in extra_context.items():
       
   173         if callable(value):
       
   174             c[key] = value()
       
   175         else:
       
   176             c[key] = value
       
   177     return HttpResponse(t.render(c), mimetype=mimetype)
       
   178 
       
   179 def archive_week(request, year, week, queryset, date_field,
       
   180         template_name=None, template_loader=loader,
       
   181         extra_context=None, allow_empty=True, context_processors=None,
       
   182         template_object_name='object', mimetype=None, allow_future=False):
       
   183     """
       
   184     Generic weekly archive view.
       
   185 
       
   186     Templates: ``<app_label>/<model_name>_archive_week.html``
       
   187     Context:
       
   188         week:
       
   189             (date) this week
       
   190         object_list:
       
   191             list of objects published in the given week
       
   192     """
       
   193     if extra_context is None: extra_context = {}
       
   194     try:
       
   195         tt = time.strptime(year+'-0-'+week, '%Y-%w-%U')
       
   196         date = datetime.date(*tt[:3])
       
   197     except ValueError:
       
   198         raise Http404
       
   199 
       
   200     model = queryset.model
       
   201     now = datetime.datetime.now()
       
   202 
       
   203     # Calculate first and last day of week, for use in a date-range lookup.
       
   204     first_day = date
       
   205     last_day = date + datetime.timedelta(days=7)
       
   206     lookup_kwargs = {
       
   207         '%s__gte' % date_field: first_day,
       
   208         '%s__lt' % date_field: last_day,
       
   209     }
       
   210 
       
   211     # Only bother to check current date if the week isn't in the past and future objects aren't requested.
       
   212     if last_day >= now.date() and not allow_future:
       
   213         lookup_kwargs['%s__lte' % date_field] = now
       
   214     object_list = queryset.filter(**lookup_kwargs)
       
   215     if not object_list and not allow_empty:
       
   216         raise Http404
       
   217     if not template_name:
       
   218         template_name = "%s/%s_archive_week.html" % (model._meta.app_label, model._meta.object_name.lower())
       
   219     t = template_loader.get_template(template_name)
       
   220     c = RequestContext(request, {
       
   221         '%s_list' % template_object_name: object_list,
       
   222         'week': date,
       
   223     })
       
   224     for key, value in extra_context.items():
       
   225         if callable(value):
       
   226             c[key] = value()
       
   227         else:
       
   228             c[key] = value
       
   229     return HttpResponse(t.render(c), mimetype=mimetype)
       
   230 
       
   231 def archive_day(request, year, month, day, queryset, date_field,
       
   232         month_format='%b', day_format='%d', template_name=None,
       
   233         template_loader=loader, extra_context=None, allow_empty=False,
       
   234         context_processors=None, template_object_name='object',
       
   235         mimetype=None, allow_future=False):
       
   236     """
       
   237     Generic daily archive view.
       
   238 
       
   239     Templates: ``<app_label>/<model_name>_archive_day.html``
       
   240     Context:
       
   241         object_list:
       
   242             list of objects published that day
       
   243         day:
       
   244             (datetime) the day
       
   245         previous_day
       
   246             (datetime) the previous day
       
   247         next_day
       
   248             (datetime) the next day, or None if the current day is today
       
   249     """
       
   250     if extra_context is None: extra_context = {}
       
   251     try:
       
   252         tt = time.strptime('%s-%s-%s' % (year, month, day),
       
   253                            '%s-%s-%s' % ('%Y', month_format, day_format))
       
   254         date = datetime.date(*tt[:3])
       
   255     except ValueError:
       
   256         raise Http404
       
   257 
       
   258     model = queryset.model
       
   259     now = datetime.datetime.now()
       
   260 
       
   261     if isinstance(model._meta.get_field(date_field), DateTimeField):
       
   262         lookup_kwargs = {'%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max))}
       
   263     else:
       
   264         lookup_kwargs = {date_field: date}
       
   265 
       
   266     # Only bother to check current date if the date isn't in the past and future objects aren't requested.
       
   267     if date >= now.date() and not allow_future:
       
   268         lookup_kwargs['%s__lte' % date_field] = now
       
   269     object_list = queryset.filter(**lookup_kwargs)
       
   270     if not allow_empty and not object_list:
       
   271         raise Http404
       
   272 
       
   273     # Calculate the next day, if applicable.
       
   274     if allow_future:
       
   275         next_day = date + datetime.timedelta(days=1)
       
   276     elif date < datetime.date.today():
       
   277         next_day = date + datetime.timedelta(days=1)
       
   278     else:
       
   279         next_day = None
       
   280 
       
   281     if not template_name:
       
   282         template_name = "%s/%s_archive_day.html" % (model._meta.app_label, model._meta.object_name.lower())
       
   283     t = template_loader.get_template(template_name)
       
   284     c = RequestContext(request, {
       
   285         '%s_list' % template_object_name: object_list,
       
   286         'day': date,
       
   287         'previous_day': date - datetime.timedelta(days=1),
       
   288         'next_day': next_day,
       
   289     }, context_processors)
       
   290     for key, value in extra_context.items():
       
   291         if callable(value):
       
   292             c[key] = value()
       
   293         else:
       
   294             c[key] = value
       
   295     return HttpResponse(t.render(c), mimetype=mimetype)
       
   296 
       
   297 def archive_today(request, **kwargs):
       
   298     """
       
   299     Generic daily archive view for today. Same as archive_day view.
       
   300     """
       
   301     today = datetime.date.today()
       
   302     kwargs.update({
       
   303         'year': str(today.year),
       
   304         'month': today.strftime('%b').lower(),
       
   305         'day': str(today.day),
       
   306     })
       
   307     return archive_day(request, **kwargs)
       
   308 
       
   309 def object_detail(request, year, month, day, queryset, date_field,
       
   310         month_format='%b', day_format='%d', object_id=None, slug=None,
       
   311         slug_field='slug', template_name=None, template_name_field=None,
       
   312         template_loader=loader, extra_context=None, context_processors=None,
       
   313         template_object_name='object', mimetype=None, allow_future=False):
       
   314     """
       
   315     Generic detail view from year/month/day/slug or year/month/day/id structure.
       
   316 
       
   317     Templates: ``<app_label>/<model_name>_detail.html``
       
   318     Context:
       
   319         object:
       
   320             the object to be detailed
       
   321     """
       
   322     if extra_context is None: extra_context = {}
       
   323     try:
       
   324         tt = time.strptime('%s-%s-%s' % (year, month, day),
       
   325                            '%s-%s-%s' % ('%Y', month_format, day_format))
       
   326         date = datetime.date(*tt[:3])
       
   327     except ValueError:
       
   328         raise Http404
       
   329 
       
   330     model = queryset.model
       
   331     now = datetime.datetime.now()
       
   332 
       
   333     if isinstance(model._meta.get_field(date_field), DateTimeField):
       
   334         lookup_kwargs = {'%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max))}
       
   335     else:
       
   336         lookup_kwargs = {date_field: date}
       
   337 
       
   338     # Only bother to check current date if the date isn't in the past and future objects aren't requested.
       
   339     if date >= now.date() and not allow_future:
       
   340         lookup_kwargs['%s__lte' % date_field] = now
       
   341     if object_id:
       
   342         lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id
       
   343     elif slug and slug_field:
       
   344         lookup_kwargs['%s__exact' % slug_field] = slug
       
   345     else:
       
   346         raise AttributeError("Generic detail view must be called with either an object_id or a slug/slugfield")
       
   347     try:
       
   348         obj = queryset.get(**lookup_kwargs)
       
   349     except ObjectDoesNotExist:
       
   350         raise Http404("No %s found for" % model._meta.verbose_name)
       
   351     if not template_name:
       
   352         template_name = "%s/%s_detail.html" % (model._meta.app_label, model._meta.object_name.lower())
       
   353     if template_name_field:
       
   354         template_name_list = [getattr(obj, template_name_field), template_name]
       
   355         t = template_loader.select_template(template_name_list)
       
   356     else:
       
   357         t = template_loader.get_template(template_name)
       
   358     c = RequestContext(request, {
       
   359         template_object_name: obj,
       
   360     }, context_processors)
       
   361     for key, value in extra_context.items():
       
   362         if callable(value):
       
   363             c[key] = value()
       
   364         else:
       
   365             c[key] = value
       
   366     response = HttpResponse(t.render(c), mimetype=mimetype)
       
   367     populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name))
       
   368     return response