Django FormWizard and Permissions - django

I was wondering if there is a way to use permission decorators for Django's FormWizard. I know there is a way to do it via the urlconf, but I would like to avoid this and have my permissions all set up via the views.
I tried to override MyFormWizard.as_view() and add the decorators there, but then realised that as_view() is a #classonlymethod.
I don't have a lot of experience with Class Based Views and was wondering if there is an easy way to add the permission decorator on one of the FormWizard's methods? Any clues?

You don't have to decorate the view in the url conf. You can do so in your views.py,
protected_wizard_view = login_required(MyWizardView.as_view())
and then import protected_wizard_view in your urls.py.
(r'^wizard/', protected_wizard_view),
Another other option is to decorate the dispatch method, as described in the docs.
class MyWizardView(WizardView):
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(MyWizardView, self).dispatch(*args, **kwargs)

#Alasdair response is good, there's also a great app that contains many helpers and mixins that you can use for Class Based View, take a look here.
Run pip install django-braces and you can use LoginRequiredMixin
from braces.views import LoginRequiredMixin
class MyWizardView(LoginRequiredMixin, WizardView):
pass
There's also mixins like PermissionRequiredMixin, MultiplePermissionsRequiredMixin, GroupRequiredMixin ...

Related

Using Multiple Decorators in urls.py in Django

I have an admin mixin that I'm using to prevent caching and make sure users are logged in by overriding dispatch(). It's being used in my class-based views.
# mixins.py
from django.contrib.admin.views.decorators import staff_member_required
from django.utils.decorators import method_decorator
from django.views.decorators.cache import never_cache
class AdminPageMixin(object):
#method_decorator(never_cache)
#method_decorator(staff_member_required)
def dispatch(self, request, *args, **kwargs):
return super(AdminPageMixin, self).dispatch(request, *args, **kwargs)
# views.py
class SomeAdminView(AdminPageMixin, ListView):
I'm running into a problem when I'm trying to run unit tests against SomeAdminView. Yes, I know I can use django's test client to login, but I'm trying to stay away from writing functional tests. I'd like, instead, to wrap AdminPageMixin functionality into a single decorator and call that decorator in urls.py, like so:
url(r'^myurl/$', decorator_wrapper(SomeAdminView.as_view()), name='some-admin-view'),
Alternatively, I could do this:
url(r'^myurl/$', never_cache(staff_member_required(SomeAdminView.as_view())), name='some-admin-view'),
but if I wanted to add a third or forth decorator, I'd be updating a lot of lines in urls.py and repeating a lot of code.
Any ideas how to create this decorator wrapper?
It is quite against the spirit of the CBVs to use decorators in the URLconfs. Instead, use mixins to add the functionality directly to the dispatch method of the view class.

django rest framework simulate required_permissions

often when i define permissions on my django views I would use something like this
#permission_required('comment.add_thread', raise_exception=True)
def save_comment(request, id=None):
""" """
But, when rest framework, how can I tell the API method to check for comment.add_thread permission before performing the operation?
It all depends how you create your api views, if your view is not generic, then you need to create your own permission like this:
from rest_framework import permissions
class AddCommentPermission(permissions.BasePermission):
def has_permission(self, request, view):
return request.user.has_perm('comment.add_thread')
but if your view has a model property set, then you just simply use DjangoModelPermissions, as documented here:
http://django-rest-framework.org/api-guide/permissions.html#djangomodelpermissions

Having multiple decorators in Django and using only one

I am using django-tokenapi to allow for authentication of an Android project that is using Django as a backend. The project also has a web interface.
django-tokenapi uses the #token_required decorator to protect certain views. Django uses the #login_required decorator to protect certain views.
What I would like is to have only one view that is protected by #login_required OR #token_required so it can be used with either the webapp or Android app.
So, ideally, it would look like this:
#token_required
#login_required
def names_update(request):
....
....
However that does not work. Is there a better method of doing this? Or is the correct thing to have two views, one the webapp and one for Android, that are protected by the proper decorator, and then lead to the same method.
No there's no easy way, if possible at all, to write an generalized OR decorator according to you described.
However, you can write a new decorator that does exactly what you want:
from functools import wraps
from django.contrib.auth import authenticate, login
from django.views.decorators.csrf import csrf_exempt
def token_or_login_required(view_func):
"""
Decorator which ensures the user is either logged in or
has provided a correct user and token pair.
"""
#csrf_exempt
#wraps(view_func)
def _wrapped_view(request, *args, **kwargs):
user = request.REQUEST.get('user')
if user and user.is_authenticated:
return view_func(request, *args, **kwargs)
token = request.REQUEST.get('token')
if user and token:
user = authenticate(pk=user, token=token)
if user:
login(request, user)
return view_func(request, *args, **kwargs)
return HttpResponseForbidden()
return _wrapped_view
this decorate combines both token_required and login_required decorators, and will allow access to the view either if the user is logged in, or the token is valid.
You could try assigning a new view variable to the old view:
#token_required
def names_update_token(request):
...
#login_required
names_update_login = names_update_token
This should have the effect of creating a second view named names_update_login which is just a pointer to the first so that the code remains the same.
EDIT:
Another thought, and one I have used, is to create a more "generic" view and call it from each of the other views:
def update_token(request):
...
#token_required
def names_update_token(request):
update_token(request)
#login_required
def names_update_login(request):
update_token(request)
This gets around the issue you mentioned while still maintaining only a single copy of the actual code that implements the view.
It is possible to use more than one decorator on a single view. But in this case I think you should seperate the view and apply the decorators seperately. Otherwise token_required decorator will try to authenticate using token which won't be available on a request made using browser.

What's the difference between the two methods of decorating class-based views?

I'm writing a view that inherits from ListView, and am trying to restrict the view to logged-in users.
https://docs.djangoproject.com/en/dev/topics/class-based-views/#decorating-in-urlconf says that decorating with login_required in the URLconf "applies the decorator on a per-instance basis. If you want every instance of a view to be decorated, you need to take a different approach" -that approach being to decorate the dispatch method in the view code.
I thought I knew the difference between a class and an instance but this phrase doesn't mean anything to me. Could someone clarify? Apart from having a decorator in the URLconf as opposed to in your class definition, what are the differences between the two approaches?
The paragraph above that link seems to answer the question: "Since class-based views aren't functions, decorating them works differently depending on if you're using as_view or creating a subclass."
Really?? I seem to be able to use the URLconf approach with my subclass of ListView.
Imagine you have the following class based view:
class PostListView(ListView):
model = Post
ProtectedPostListView = login_required(PostListView.as_view())
and your urls.py:
url(r'posts$', ProtectedPostListView)
If you use this approach then you lose the ability to subclass ProtectedPostListView e.g
class MyNewView(ProtectedPostListView):
#IMPOSSIBLE
and this is because the .as_view() returns a function and after applying the login_required decorator you are left with a function, so subclassing is not possible.
On the other hand if you go with the second approach i.e use the method decorator the subclassing is possible.
e.g
class PostListView(ListView):
model = Post
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(PostListView, self).dispatch(*args, **kwargs)
class MyNewView(PostListView):
#LEGAL

How to specify that login is required somewhere other than a view in Django?

So I have an app called stats that lets me query my database in various ways and return information in a JSON format so I can have a nice ajaxy dashboard for graphing and visualizing. I'd like this app to be as reusable as possible, naturally, so I don't want to necesarily use the #login_required decorator on its views. In my case, however, I do want a login to be required before viewing any of the apps views. Is there a way to do this somewhere other than the views?
Perhaps something like this in my site's urls.py? (I know this won't work, an example of what I'm looking for)
urlpatterns = patterns('',
(r'^stat/', include('stats.urls'), login_required),
)
You can apply decorator for individual urls in urls.py in this manner:
from django.contrib.auth.decorators import login_required
import views
(r'^stat/', login_required(views.index))
you can use a middleware for that
here is example snippet - http://www.djangosnippets.org/snippets/1179/
you can use this snippet and define LOGIN_EXEMPT_URLS in your settings or modifiy it a little bit for your case
If you're concerned about reusability, rather than using login_required, you could use a decorator which requires login if a particular argument is passed to the view (which might default to a value of True). Off the top of my head, it might look a little like this:
from django.contrib.auth.decorators import login_required
def login_possibly_required(view_func):
def inner(request, *args, **kwargs):
try:
require_login = kwargs.pop('require_login')
if require_login:
return login_required(view_func)(request, *args, **kwargs)
except KeyError:
pass
return view_func(request, *args, **kwargs)
return inner
Then you'd define your views like so:
#login_possibly_required
my_view(request, arg1, arg2, require_login=True):
pass
Not tested, but you get the idea.