convert function to decorator django - django

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):
...

Related

How to choose which decorator to apply based on condition?

Can decorators be applied based on condition ? Below is a trivial example:
import os
def bold_decorator(fn):
def wrapper(*args, **kwargs):
return '**' + fn(*args, **kwargs) + '**'
return wrapper
def italic_decorator(fn):
def wrapper(*args, **kwargs):
return '_' + fn(*args, **kwargs) + '_'
return wrapper
if os.environ.get('STYLE'):
#bold_decorator
else:
#italic_decorator
def create_text(text=''):
return text
if __name__ == '__main__':
print(create_text('Decorator decisions'))
What I want is, when environment variable is set, to apply bold_decorator. And when it's not set, use italic_decorator. I'm using Flask framework for JWTs which has decorators jwt_required and jwt_optional in which I can't modify source of these decorators. I'm trying to find solution to this problem. Any help would be appreciated
For the specific case of flask-jwt-extended, you could do the if/else logic in your own custom decorator which is then applied to all your view functions. You can view the full docs for that here (https://flask-jwt-extended.readthedocs.io/en/stable/custom_decorators/) but it might look something like this:
from flask_jwt_extended import (
verify_jwt_in_request,
verify_jwt_in_request_optional
)
def custom_jwt_required(fn):
#wraps(fn)
def wrapper(*args, **kwargs):
if os.environ.get('ALLOW_OPTIONAL_JWT'):
verify_jwt_in_request_optional()
else:
verify_jwt_in_request()
return fn(*args, **kwargs)
return wrapper
For a more general case, you could do this at the import level. Something like:
if os.environ.get('STYLE'):
from decorators import bold_decorator as decorator
else:
from decorators import italic_decorator as decorator
#decorator
def create_text(test=''):
return text

Django view argument in decorator

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.

Django, let decorator value be available in view function

I have a decorator:
def site_login_required(function=None):
def _dec(view_func):
def _view(request, *args, **kwargs):
gets site_id. checks stuff. if else.
This is called in the normal way:
#site_login_required
def frontPage(request, url_arg):
The decorator finds a site_id. It would be nice to have this available in the frontPage function. Is that possible? If so how?
You could pass it in as a kwarg when you call the view function within the decorator:
def site_login_required(function=None):
def _dec(view_func):
def _view(request, *args, **kwargs):
site_id = get_site_id()
url_arg = get_a_url()
view_func(request, url_arg, site_id=site_id)
#site_login_required
def frontPage(request, url_arg, site_id=None, *args, **kwargs):
...
As a side note, it is useful to accept *args and **kwargs in all view functions, so they consume extra arguments instead of choking with decorators like this wrapped around them.

How to write a decorator for a class based view -- permision based on object from view

right now I'm using this app for permission checking: django-rules
However it hasn't been updated for over a year now and there's no decorator for the "new" (since django 1.3) class based views. I would like to be able to use at the urls.py like this:
url(r'^casos/(?P<pk>\d+)/editar/$', rules_permission_required('lawsuits.logical_check', raise_exception=True)(CaseUpdateView.as_view()), name='case_edit'),
I can't figure out how to get the object from the class based view from the decorator. Do you guys have any idea? Here's what I have so far:
from django.utils.decorators import available_attrs
def rules_permission_required(perm, queryset=None, login_url=None, raise_exception=False):
def wrapper(view_func):
#wraps(view_func, assigned=available_attrs(view_func))
def inner(request, *args, **kwargs):
#view_func is the class based view -> <function MyEditView at 0x94e54c4>
print view_func.get_object() # doesnt work
print view_func(request, *args, **kwargs).get_object() # doesnt work either
#any ideas?
if not request.user.has_perm(perm, obj=obj):
return redirect_to_login(request, login_url, raise_exception)
return view_func(request, *args, **kwargs)
return inner
return wrapper
Many thanks in advance!
Use method_decorator on the dispatch() method: https://docs.djangoproject.com/en/dev/topics/class-based-views/#decorating-class-based-views
from django.utils.decorators import method_decorator
class ClassBasedView(View):
#method_decorator(rules_permission_required)
def dispatch(self, *args, **kwargs):
return super(ClassBasedView, self).dispatch(*args, **kwargs)
Or you could decorate the output of the as_view class method, either in your url config (as described in the link above), or by saving the instance into a variable.
class ClassBasedView(View):
def dispatch(self, *args, **kwargs):
return super(ClassBasedView, self).dispatch(*args, **kwargs)
class_based_view = rules_permission_required(ClassBasedView.as_view())
Though I'm not quite sure whether the last example could cause thread safety problems (depends on how Django handles the instances). The best way is probably to stick with the method_decorator.
I ended up using a class decorator
def rules_permission_required(perm, queryset=None, login_url=None, raise_exception=False):
def wrapper(cls):
def view_wrapper(view_func):
#wraps(view_func, assigned=available_attrs(view_func))
def inner(self, request, *args, **kwargs):
# get object
obj = get_object_from_classbased_instance(
self, queryset, request, *args, **kwargs
)
# do anything you want
return inner
cls.dispatch = view_wrapper(cls.dispatch)
return cls
return wrapper

Wrapping/decorating a function in urls.py vs in views.py

So, I'm pretty familiar with wrapping functions in views.py. So I've written a decorator to redirect to the default REDIRECT_URL if the user is logged in (sort of a reverse login_required); it's based on how I've made views in the past:
def not_logged_in(redirect_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
def decorator(view_func, *args, **kwargs):
def wrapper(request, *args, **kwargs):
if not request.user.is_authenticated():
return view_func(*args, **kwargs)
else:
redirect_url = (request.REQUEST.get(redirect_field_name, redirect_url) or
settings.REDIRECT_URL)
return HttpResponseRedirect(redirect_url)
return wrapper
return decorator
However, I get the following error: 'function' object has no attribute 'status_code' which is caused by a MiddleWare expecting an HttpResponse. When I look at the value for response, I see that it's <function wrapper at 0x2b3a9922a500>.
Here's how I'm calling it in urls.py:
url(r'login/',
not_logged_in(auth_views.login),
{'authentication_form': LoginForm },
),
Here’s my implementation of the same thing.
def logout_required(view):
def f(request, *args, **kwargs):
if request.user.is_anonymous():
return view(request, *args, **kwargs)
return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL)
return f
In urls.py:
urlpatterns = patterns("",
url(r"^login/", logout_required(login), {"template_name": "users/login.html"}, "login"),
# ...
I hope this helps (unsure though).
The first argument to a decorator should be the function that needs to be decorated.
def not_logged_in(func, redirect_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
The decorator function is also not needed. Return the wrapper function from not_logged_in.
The way you've implemented your decorator, it is parameterised and therefore callable: that's why you've got the extra level of function that fizixx wrongly says is not required. You need to call the outer wrapper initially, in order to return the actual decorated function. So something like:
url(r'login/',
not_logged_in(auth_views.login)('/redirect/', 'redirect_field'),
{'authentication_form': LoginForm },
),