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