root/lang/python/gae_django/views/generic/date_based.py

Revision 9873, 17.3 kB (checked in by ueblog, 15 months ago)

lang/python/gae_django date_based archive_today change

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