PageRenderTime 222ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/views/generic/date_based.py

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