am having a function ill like to make into a decorator with an argument please can any one help with this
def get_permission(request,permission_level):
if has_permission(request,permission_level):#this is another function
#my work will be done here
else:
raise Http404
and ill just want to use it in my view like this
#get_permission(permission_level)
def a_view(request)
can any one help out on this please? thanks
Take a look at django/contrib/auth/decorators.py, something like
from functools import wraps
from django.utils.decorators import available_attrs
def get_permission(permission_level):
def decorator(func):
#wraps(func, assigned=available_attrs(func))
def _wrapped(request, *args, **kwargs):
if has_permission(request, permission_level):
'special logic goes here...'
return func(request, *args, **kwargs)
else:
raise Http404
Check How to make a chain of function decorators? and PEP 318 for writing decorators.
Or you could take advantage of user_passes_test or permission_required in django/contrib/auth/decorators.py directly, if the decorator just checks the permission to determine the result to return.
Related
I am many views and more than one user type. I want some views that can be seen by specific user types and other users cant see this.
For example, only company see this views and for this i did that like this below:
#login_required
def only_company_can_view(request):
if not Company.objects.filter(owner_id=request.user.id).exists():
return HttpResponse('Permission Denied. Only Company can see this')
# > rest of the logic
return render(request, 'template.html')
and above this working very well and solves my problem but i don't like this. coz, i don't want to write every time for the rest of the views for the company related views.
So i am finding a solution so that i can use decorator or something else that are best practice
Can anyone help me in this case?
You can wrap the logic in a decorator:
from django.core.exceptions import PermissionDenied
from functools import wraps
def requires_company(view):
#wraps(view)
def _view(request, *args, **kwargs):
if not Company.objects.filter(owner_id=request.user.id).exists():
raise PermissionDenied
return view(request, *args, **kwargs)
return _view
Then you use the decorator with:
#login_required
#requires_company
def only_company_can_view(request):
# … rest of the logic …
return render(request, 'template.html')
I am using class based views in Django. #login_required decorator is not redirecting to login page. It still shows the profile page.
class ProfileView(TemplateView):
template_name='profile.html'
#login_required(login_url='/accounts/login/')
def dispatch(self, *args, **kwargs):
return super(ProfileView, self).dispatch(*args, **kwargs)
Can anyone help me. I m new to Django and any help would be appreciated.
Thanks in advance
You need to apply a method_decorator first and then pass it the login_required function decorator.
A method on a class isn’t quite the same as a standalone function, so you can’t just apply a function decorator to the method. You need to transform it into a method decorator first.
To make it more clear, Django's view decorators return a function with a signature (request, *args, **kwargs) but for class based-views, the signature should be of the form (self, request, *args, **kwargs). Now, what the method_decorator does is that it transforms the first signature to the second.
From docs on decorating Class-based Views:
The method_decorator decorator transforms a function decorator into
a method decorator so that it can be used on an instance method.
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
class ProfileView(TemplateView):
template_name='profile.html'
#method_decorator(login_required(login_url='/accounts/login/'))
def dispatch(self, *args, **kwargs):
return super(ProfileView, self).dispatch(*args, **kwargs)
When using class-based views, it's preferred to use the LoginRequiredMixin rather than the #login_required decorator. It performs essentially the same function.
class ProfileView(LoginRequiredMixin, TemplateView):
template_name='profile.html'
I'm converting some FBVs with signals to CBVs, so I have this decorator:
def ensure_https(view_func):
def _checkssl(request, *args, **kwargs):
print request.is_secure()
if not settings.DEBUG and not request.is_secure():
url_str = request.build_absolute_uri()
url_str = url_str.replace('http://', 'https://')
return HttpResponseRedirect(url_str)
return view_func(request, *args, **kwargs)
return _checkssl
and added it to a function in a class based view, as so:
class ExampleTemplateView(TemplateView):
template_name = 'example.html'
#ensure_https
def dispatch(self, request, *args, **kwargs):
...
return HttpResponseRedirect(/hello/')
But I get the following error:
'ExampleTemplateView' object has no attribute 'is_secure'
However, when I use this decorator on a function-based view, it works just fine. Should I be using a particular CBV?
If you need anymore code or info, please let me know. Thanks for your help!
I think you have signal and decorator confused as the pattern in your code is a decorator. Depending on what you're doing there might be better alternatives to where you put the URL redirection logic. I'm thinking webserver(nginx), HTTP Strict Transport Security HTTP header or middleware. Having said that, from the django docs:
To decorate every instance of a class-based view, you need to decorate
the class definition itself. To do this you apply the decorator to the
dispatch() method of the class.
A method on a class isn’t quite the same as a standalone function, so
you can’t just apply a function decorator to the method – you need to
transform it into a method decorator first. The method_decorator
decorator transforms a function decorator into a method decorator so
that it can be used on an instance method. For example:
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
class ProtectedView(TemplateView):
template_name = 'secret.html'
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(ProtectedView, self).dispatch(*args, **kwargs)
I have specific subjects related with specific users in my application. How to limit their access to just their subjects?
I have idea to use like
usersub = get_object_or_404(UserSubject, user=request.user, subject=subject)
If there is no relation, it will throw 404 error. But is there any other way to complete it with user_passes_test decorator?
Well, you can use exists
if UserSubject.objects.filter(user=request.user, subject=subject).exists():
# what you want to do
else:
# do something else
or just filter
usersub = UserSubject.objects.filter(user=request.user, subject=subject)
if usersub:
# do something
else:
# do something else
Those will make your check but will not raise an Exception or return a Http404.
Update: You must write your own decorator, since user_passes_test can nor handle your situation. Here is an example decorator:
from django.http import HttpResponseForbidden
def subject_test(f, subject):
def test_user_for_subject(request, subject, *args, **kwargs):
if not UserSubject.objects.filter(user=request.user, subject=subject).exists():
retun HttpResponseForbidden('Access denied!')
else:
return f(request, *args, **kwargs)
return test_user_for_subject
An in your views :
#subject_test('your subject here')
def your_view_is_in_here(request):
...
But the hard part is, you must pass all your filter arguments unless they are reachable from request
I want to do this:
#friendship_required
or
#friendship_required(request)
Can any one help me make this simple function into a decorator I think I will be using it a lot and feel it's better to make it into a decorator, or how I may set the return statement if hasattr is in my settings file? Thanks
def friendship_checker(request):
if hasattr(request.user,'friend'):
pass
else:
return HttpResponseRedirect('/access-denied')
from functools import wraps
def friendship_checker(f):
#wraps(f)
def wrapped(request, *args, **kwargs):
if hasattr(request.user, 'friend'):
return f(request, *args, **kwargs)
else:
return HttpResponseRedirect('/access-denied')
return wrapped
So, to decorate a view:
#friendship_checker
def my_view(request):
...