views.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. # -*- coding: utf-8 -*-
  2. from __future__ import absolute_import
  3. from __future__ import division
  4. from __future__ import print_function
  5. from __future__ import unicode_literals
  6. from django.conf import settings
  7. from django.contrib.contenttypes.models import ContentType
  8. from django.shortcuts import get_object_or_404, redirect
  9. from django.views import generic
  10. from django.core.exceptions import PermissionDenied
  11. from django.template import RequestContext
  12. from django.utils.http import urlquote_plus
  13. from django.template import loader
  14. from django.http import HttpResponse
  15. from rapid.models import DocumentTemplate
  16. from rapid.officedocs.rtf import RtfTemplate
  17. from rapid.wrappers import InstanceData, ModelData
  18. from rapid.filters import FilterSet
  19. from rapid.rapidforms import for_model
  20. import math
  21. from os import path
  22. def _build_uri(request, params):
  23. param_string = "&".join(["%s=%s" % (urlquote_plus(k), urlquote_plus(params[k])) for k in params.keys()])
  24. base = request.build_absolute_uri().split("?")[0]
  25. return base + "?" + param_string
  26. def _copy_dict(dc):
  27. d = {}
  28. for k in dc.keys():
  29. d[k] = dc[k]
  30. return d
  31. def _replace_param(request, param_name, param_value):
  32. get = _copy_dict(request.GET)
  33. get[param_name] = param_value
  34. return _build_uri(request, get)
  35. def is_ajax_request(request):
  36. # X-Requested-With: XMLHttpRequest
  37. w = request.META.get('HTTP_X_REQUESTED_WITH')
  38. if w:
  39. return True
  40. return False
  41. class ListView(generic.list.ListView):
  42. template_name = 'rapid/bare/list.html'
  43. action_name = ''
  44. registers_per_page = 50
  45. number_of_edge_pages = 5
  46. number_of_middle_pages = 5
  47. fields = None
  48. class Pagination(object):
  49. def __init__(self, request, page, number_of_edge_pages, number_of_middle_pages,
  50. registers_per_page, total_pages):
  51. self.request = request
  52. self.number_of_edge_pages = number_of_edge_pages
  53. self.number_of_middle_pages = number_of_middle_pages
  54. self.registers_per_page = registers_per_page
  55. self.page = page
  56. self.total_pages = total_pages
  57. def _page_and_uri(self, pages):
  58. get2 = _copy_dict(self.request.GET)
  59. for p in pages:
  60. get2['page'] = p
  61. yield (p, _build_uri(self.request, get2))
  62. def start_numbers(self):
  63. """
  64. Page numbers listed at the beginning of the pagination area
  65. """
  66. e = self.number_of_edge_pages
  67. for i in range(1, min(e+1, self.page)):
  68. yield i
  69. def start(self):
  70. """
  71. Page numbers and URLs listed at the beginning of the pagination area
  72. """
  73. return self._page_and_uri(self.start_numbers())
  74. def before_numbers(self):
  75. """
  76. Page numbers listed at the pagination area before the current page
  77. """
  78. m = self.number_of_middle_pages
  79. for i in range(max(self.page - m, m), self.page):
  80. yield i
  81. def before(self):
  82. """
  83. Page numbers and URLs listed at the pagination area before the current page
  84. """
  85. return self._page_and_uri(self.before_numbers())
  86. def after_numbers(self):
  87. """
  88. Page numbers listed at the pagination area after the current page
  89. """
  90. m = self.number_of_middle_pages
  91. e = self.number_of_edge_pages
  92. for i in range(self.page + 1, min(self.page + m + 1, self.total_pages - e + 1)):
  93. yield i
  94. def after(self):
  95. """
  96. Page numbers and URLs listed at the pagination area after the current page
  97. """
  98. return self._page_and_uri(self.after_numbers())
  99. def end_numbers(self):
  100. """
  101. Page numbers listed at the end of the pagination area
  102. """
  103. e = self.number_of_edge_pages
  104. for i in range(max(self.page + 1, self.total_pages - e + 1), self.total_pages + 1):
  105. yield i
  106. def end(self):
  107. """
  108. Page numbers and URLs listed at the end of the pagination area
  109. """
  110. return self._page_and_uri(self.end_numbers())
  111. def separate_end(self):
  112. """
  113. True if there's a separator between the next pages and the end pages.
  114. """
  115. return self.page < self.total_pages - self.number_of_edge_pages - self.number_of_middle_pages
  116. def separate_start(self):
  117. """
  118. True if there's a separator between the start pages and the before pages.
  119. """
  120. return self.page > self.number_of_edge_pages + self.number_of_middle_pages
  121. def get_page(self, queryset):
  122. return queryset[self.registers_per_page*(self.page-1):self.registers_per_page*self.page]
  123. class View(object):
  124. order_param = 'order'
  125. def __init__(self, request, action_name, model, queryset, fields, pagination):
  126. self.request = request
  127. self.model = model
  128. self.action_name = action_name
  129. self._fields = fields
  130. q = queryset
  131. self.filters = FilterSet.from_request(ModelData(self.model), request)
  132. if self.filters:
  133. q = q.filter(**self.filters.query_dict())
  134. self.queryset = q
  135. total = q.count()
  136. pagination.total_pages = int(math.ceil(total / pagination.registers_per_page))
  137. order = request.GET.get(self.order_param)
  138. if order:
  139. q = q.order_by(order)
  140. self.queryset = pagination.get_page(q)
  141. def values(self):
  142. for o in self.queryset:
  143. if self._fields:
  144. c = InstanceData(o, request=self.request, fields=self._fields)
  145. else:
  146. c = InstanceData(o, request=self.request)
  147. if c.has_permission(self.request, self.action_name):
  148. yield c
  149. def fields(self):
  150. order_param = self.order_param
  151. request = self.request
  152. class FieldParams(object):
  153. def __init__(self, field):
  154. self.field = field
  155. def order_up_url(self):
  156. return _replace_param(request, order_param, self.field.bare_name())
  157. def order_down_url(self):
  158. return _replace_param(request, order_param, '-' + self.field.bare_name())
  159. def add_filter_url(self):
  160. pass
  161. def del_filter_url(self):
  162. pass
  163. for f in ModelData(self.model, request=self.request, fields=self._fields).fields():
  164. f.view = FieldParams(f)
  165. yield f
  166. def get(self, request, **kwargs):
  167. mdt = ModelData(self.model, request)
  168. if not mdt.has_permission(request, self.action_name):
  169. raise PermissionDenied
  170. object_list = self.get_queryset()
  171. # Populates the context
  172. context = RequestContext(request).flatten()
  173. context.update(kwargs)
  174. total_pages = int(math.ceil(object_list.count() / self.registers_per_page))
  175. page = int(request.GET.get('page', 1))
  176. p = self.Pagination(request, page, self.number_of_edge_pages,
  177. self.number_of_middle_pages, self.registers_per_page,
  178. total_pages)
  179. context['pages'] = p
  180. context['model'] = ModelData(self.model, request, fields=self.fields)
  181. context['view'] = self.View(request, self.action_name, self.model, object_list, self.fields, p)
  182. offset = (page - 1) * self.registers_per_page
  183. self.object_list = object_list[offset: offset + self.registers_per_page]
  184. context[self.get_context_object_name(object_list)] = object_list
  185. context['object_list'] = object_list
  186. context = self.get_context_data(**context)
  187. # noinspection PyAttributeOutsideInit
  188. self.object_list = object_list
  189. return self.render_to_response(context)
  190. class ReadView(generic.detail.DetailView):
  191. template_name = 'rapid/bare/detail.html'
  192. action_name = ''
  193. request = None
  194. def get_object(self, request=None):
  195. return get_object_or_404(self.model, pk=self.kwargs['pk'])
  196. # noinspection PyMethodOverriding
  197. def get(self, request, pk, **kwargs):
  198. context = RequestContext(request).flatten()
  199. context.update(kwargs)
  200. obj = self.get_object(self.request)
  201. context['object'] = obj
  202. context[self.get_context_object_name(obj)] = obj
  203. cd = InstanceData(obj, request=request)
  204. if not cd.has_permission(request, self.action_name):
  205. raise PermissionDenied
  206. excludes = request.GET.get('exclude')
  207. if excludes:
  208. cd.excludes = excludes.split(",")
  209. # noinspection PyAttributeOutsideInit
  210. self.object = cd
  211. context['object_data'] = cd
  212. context = self.get_context_data(**context)
  213. return self.render_to_response(context)
  214. class CreateView(generic.edit.CreateView):
  215. template_name = 'rapid/bare/create.html'
  216. action_name = ''
  217. object = None
  218. fields = '__all__'
  219. def request_form(self, request):
  220. return for_model(request, self.model)
  221. def get(self, request, **kwargs):
  222. context = RequestContext(request).flatten()
  223. context.update(kwargs)
  224. cd = ModelData(self.model, request=request)
  225. if not cd.has_permission(request, self.action_name):
  226. raise PermissionDenied
  227. context['model_data'] = cd
  228. if request.POST:
  229. context['form'] = self.request_form(request)(request.POST, request.FILES)
  230. else:
  231. context['form'] = self.request_form(request)()
  232. context = self.get_context_data(**context)
  233. return self.render_to_response(context)
  234. def post(self, request, **kwargs):
  235. m = ModelData(self.model, request=request)
  236. if m.has_permission(request, self.action_name):
  237. f = self.request_form(request)(request.POST, request.FILES)
  238. if f.is_valid():
  239. f.save()
  240. return redirect(m.list_url())
  241. return self.get(request, **kwargs)
  242. raise PermissionDenied()
  243. class UpdateView(generic.edit.UpdateView):
  244. template_name = 'rapid/bare/update.html'
  245. action_name = ''
  246. fields = '__all__'
  247. def get_object(self, queryset=None):
  248. return get_object_or_404(self.model, pk=self.kwargs['pk'])
  249. def request_form(self, request):
  250. return for_model(request, self.model)
  251. # noinspection PyMethodOverriding
  252. def get(self, request, pk, **kwargs):
  253. context = RequestContext(request).flatten()
  254. context.update(kwargs)
  255. obj = self.get_object()
  256. context['object'] = obj
  257. context[self.get_context_object_name(obj)] = obj
  258. cd = InstanceData(obj, request=request)
  259. if not cd.has_permission(request, self.action_name):
  260. raise PermissionDenied
  261. # noinspection PyAttributeOutsideInit
  262. self.object = cd
  263. context['object_data'] = cd
  264. if request.POST:
  265. context['form'] = self.request_form(request)(request.POST, request.FILES, instance=obj)
  266. else:
  267. context['form'] = self.request_form(request)(instance=obj)
  268. context = self.get_context_data(**context)
  269. return self.render_to_response(context)
  270. # noinspection PyMethodOverriding,PyAttributeOutsideInit
  271. def post(self, request, pk, **kwargs):
  272. obj = self.get_object()
  273. m = InstanceData(obj, request=request)
  274. if m.has_permission(request, self.action_name):
  275. f = self.request_form(request)(request.POST, request.FILES, instance=obj)
  276. if f.is_valid():
  277. if f.instance.pk != obj.pk:
  278. raise PermissionDenied
  279. f.save()
  280. return redirect(m.list_url())
  281. self.form = f
  282. return self.get(request, pk, **kwargs)
  283. raise PermissionDenied
  284. class DeleteView(generic.edit.DeleteView):
  285. template_name = 'rapid/bare/delete.html'
  286. action_name = ''
  287. fields = '__all__'
  288. def __init__(self, **kwargs):
  289. super(DeleteView, self).__init__(**kwargs)
  290. self.success_url = ModelData(self.model).list_url()
  291. def get_object(self, queryset=None):
  292. return get_object_or_404(self.model, pk=self.kwargs['pk'])
  293. def has_permission(self, request, instance):
  294. return instance.has_permission(request, self.action_name)
  295. def get(self, request, *args, **kwargs):
  296. obj = InstanceData(self.get_object())
  297. if not self.has_permission(request, obj):
  298. raise PermissionDenied
  299. return super(DeleteView, self).get(request, *args, **kwargs)
  300. def post(self, request, *args, **kwargs):
  301. obj = InstanceData(self.get_object())
  302. if not self.has_permission(request, obj):
  303. raise PermissionDenied
  304. return super(DeleteView, self).post(request, *args, **kwargs)
  305. class SelectView(ListView):
  306. """
  307. A selectable list of objects.
  308. """
  309. template_name = 'rapid/bare/select.html'
  310. def bare_or_main(view):
  311. main_window_template = "rapid/main_window.html"
  312. def vw(request, *args, **kwargs):
  313. resp = view(request, *args, **kwargs)
  314. bare = is_ajax_request(request)
  315. if bare:
  316. if 300 <= resp.status_code <= 399:
  317. # I'll interpret redirects as successful POST,
  318. # thus, the response'll get replaced by something with
  319. # a header that says "success!"
  320. ret = HttpResponse('')
  321. ret['X-FORM-STATUS:'] = 'success'
  322. return ret
  323. if not bare and resp.status_code == 200 and request.method != "HEAD":
  324. if hasattr(resp, 'render'):
  325. resp.render()
  326. body = resp.content
  327. main_win = loader.get_template(main_window_template)
  328. context = RequestContext(request)
  329. context.update({'body_text': body, 'this_url': request.get_full_path()})
  330. resp.content = main_win.render(context, request)
  331. return resp
  332. return vw
  333. def update_form_class(form):
  334. class F(UpdateView):
  335. def request_form(self, request):
  336. return form
  337. return F
  338. def add_form_class(form):
  339. class F(CreateView):
  340. def request_form(self, request):
  341. return form
  342. return F
  343. class RenderDocumentView(generic.View):
  344. model = None
  345. action_name = None
  346. # noinspection PyUnusedLocal
  347. def get(self, request, pk, template):
  348. inst = get_object_or_404(self.model, pk=pk)
  349. ctx = inst.__dict__
  350. tm = get_object_or_404(DocumentTemplate, model=ContentType.objects.get_for_model(self.model), pk=template)
  351. f = path.join(settings.MEDIA_ROOT, tm.template.name)
  352. t = RtfTemplate(f, ctx)
  353. return HttpResponse(t.read(), content_type='application/rtf')
  354. def get_delete_document_template_view(model):
  355. class DeleteDocumentTemplateView(DeleteView):
  356. def get_object(self, queryset=None):
  357. # noinspection PyUnresolvedReferences
  358. return get_object_or_404(DocumentTemplate, pk=self.kwargs['pk'])
  359. def has_permission(self, request, instance):
  360. if not ModelData(model).has_permission(request, self.action_name):
  361. return False
  362. return instance.instance.model == ContentType.objects.get_for_model(model)
  363. return DeleteDocumentTemplateView