Ticket #17795: example_code.py

File example_code.py, 3.6 KB (added by ed.crewe@…, 3 years ago)

example decorator needing objects and monkeypatches to provide this

Line 
1#### Example use case: object permission check wrapper for view classes
2
3# This can be wrapped at a class level to provide a simple @permissions(perms_list)
4# decorator for class views that can be used to check request user for
5# permissions on the objects returned by the view
6
7def func_permissions(*perms):
8    """ Class function decorator to check user for object permissions
9        User must have all the permissions listed to get access.
10    """
11    def decorator(view_func):
12        @wraps(view_func, assigned=available_attrs(view_func))
13        def _inner(request=None, *args, **kwargs):
14            """ when decorating a class view_func is get_context_data
15                NB: requires dispatch decorator to set request.user in kwargs
16            """
17            obj_list = kwargs.get('object_list', [])
18            context = view_func(**kwargs)
19            if not obj_list:
20                obj = context.get('subobject', 
21                                  context.get('object', None))
22                if obj:
23                    obj_list = [obj, ]
24            user = kwargs.get('user', context.get('user', None))
25            if not user:
26                raise Denied("""No user has been passed in kwargs or context
27                                      to test %s permissions""" % str(perms))
28            if not obj_list:
29                raise Denied("""There is no object supplied in the request
30                                      to test %s permissions""" % str(perms))
31            for codename in perms:
32                for obj in obj_list:
33                    if not has_permission(obj, user, codename):
34                        raise Denied("""User '%s' doesn't have permission
35                                          '%s' for object '%s' (%s)""" 
36                                   % (user, codename, obj, obj.__class__.__name__))
37            return view_func(*args, **kwargs)
38        return _inner
39    return decorator
40
41############## Monkey patch view classes to pass kwargs for decorators #####
42
43def processformview_get(self, request, *args, **kwargs):
44    form_class = self.get_form_class()
45    form = self.get_form(form_class)
46    kwargs['form'] = form
47    context = self.get_context_data(**kwargs)
48    return self.render_to_response(context)
49
50def baselistview_get(self, request, *args, **kwargs):
51    self.object_list = self.get_queryset()
52    allow_empty = self.get_allow_empty()
53    if not allow_empty and len(self.object_list) == 0:
54        raise Http404(_(u"Empty list and '%(class_name)s.allow_empty' is False.")
55                      % {'class_name': self.__class__.__name__})
56    kwargs['object_list'] = self.object_list
57    context = self.get_context_data(**kwargs)
58    return self.render_to_response(context)
59
60def basedetailview_get(self, request, *args, **kwargs):
61    self.object = self.get_object()
62    kwargs['object'] = self.object   
63    context = self.get_context_data(**kwargs)
64    return self.render_to_response(context)
65
66def basedatelistview_get(self, request, *args, **kwargs):
67    self.date_list, self.object_list, extra_context = self.get_dated_items()
68    kwargs['object_list'] = self.object_list
69    kwargs['date_list'] = self.date_list
70    context = self.get_context_data(**kwargs)
71    context.update(extra_context)
72    return self.render_to_response(context)
73
74from django.views.generic.edit import ProcessFormView
75ProcessFormView.get = processformview_get
76from django.views.generic.list import BaseListView
77BaseListView.get = baselistview_get
78from django.views.generic.detail import BaseDetailView
79BaseDetailView.get = basedetailview_get
80from django.views.generic.dates import BaseDateListView
81BaseDateListView.get = basedatelistview_get
82
83
Back to Top