views.py 15 KB

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