Reputation: 9522
I am not very comfortable using class-based views but I am aware of their perks so I am forcing myself to start using them more often.
There's this view that receives a path param: manage/:id
to manage a particular entity.
class MyView(TemplateView):
template_name = '...'
def get_context_data(self, **kwargs):
context = super(MyView, self).get_context_data(**kwargs)
context['entity'] = get_object_or_404(Entity, pk=self.args[0])
return context
An Entity
includes a list of authorized users to perform special actions. This view, MyView
is one of those special actions.
I tried making a decorator for the view but it required finding the Entity
first so I wasn't sure how to work that out.
Now, I have a check_permission(request, entity)
function that checks if the current user is one of these authorized ones.
My question is where should I call this function in the class-based views like MyView
which will be any of these views considered "special actions"?
Should I call it just from get_context_data()
?
Upvotes: 6
Views: 5064
Reputation: 9359
put it into dispatch(). It could look like this:
class MyView(TemplateView):
template_name = '...'
def dispatch(self, request, *args, **kwargs):
entity = get_object_or_404(Entity, pk=args[0])
if not check_permission(request, entity):
raise Http404
return super(MyView, self).dispatch(request, *args, **kwargs)
Upvotes: 9
Reputation: 2214
You can check permissions in the dispatch
as yedpodtrzitko has said. I think it's also a good idea to throw it inside of a mixin that you can put on your views.
Here's an example:
from django.core.exceptions import PermissionDenied
class ViewPermissionsMixin(object):
"""Base class for all custom permission mixins to inherit from"""
def has_permissions(self):
return True
def dispatch(self, request, *args, **kwargs):
if not self.has_permissions():
raise PermissionDenied
return super(ViewPermissionsMixin, self).dispatch(
request, *args, **kwargs)
class MyCustomPermissionMixin(ViewPermissionsMixin):
def has_permissions(self):
# here you will have access to both
# self.get_object() and self.request.user
return self.request.user in self.get_object().special_list_of_people
Now you can throw MyCustomPermissionMixin
on your view:
class MyView(MyCustomPermissionMixin, TemplateView):
# ...
In your case, since you're using a TemplateView
, you should also make a get_object()
method that returns the object that you want to deal with. Template views don't have this method by default.
Finally, just want to say that you will love Django's class based views once you learn some more about how to use them.
Upvotes: 8
Reputation: 19621
Take a look at Django Braces, it's a solid set of mixins which are designed around permissions.
How specifically you deal with permissions depends largely on implementation. I've done it in dispatch() before which is the way Braces does it but if it's specific to an object or queryset, I'll do it in the actual get_object or get_queryset methods as part of a DetailView.
For example if you had a creator associated with an Entity, you could override get_object
to check the current logged in user is the Entity's creator.
class EntityView(LoginRequiredMixin, DetailView):
model = Thing
def get_object(self, **kwargs):
return Entity.objects.get_object_or_404(
pk=kwargs['entity_id'],
creator=self.request.user
)
Note: LoginRequiredMixin is a part of Braces. Very slick.
Upvotes: 1