Hi Adam,
Thanks for your response.
The only thing that makes the solution more complicated is the fact that I created a
user_passes_test function to not harm anyone who is already using that function. In order to simplify this, we could replace
user_passes_test
with the
request_passes_test function.
def request_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
"""
Decorator for views that checks that the request passes the given test,
redirecting to the log-in page if necessary. The test should be a callable
that takes the request object and returns True if the request passes.
"""
def decorator(view_func):
@wraps(view_func)
def _wrapped_view(request, *args, **kwargs):
if test_func(request):
return view_func(request, *args, **kwargs)
path = request.build_absolute_uri()
resolved_login_url = resolve_url(login_url or settings.LOGIN_URL)
# If the login url is the same scheme and net location then just
# use the path as the "next" url.
login_scheme, login_netloc = urlparse(resolved_login_url)[:2]
current_scheme, current_netloc = urlparse(path)[:2]
if ((not login_scheme or login_scheme == current_scheme) and
(not login_netloc or login_netloc == current_netloc)):
path = request.get_full_path()
from django.contrib.auth.views import redirect_to_login
return redirect_to_login(
path, resolved_login_url, redirect_field_name)
return _wrapped_view
return decorator
This function would allow to write the exact same test functions, but changing user to request.user. For example:
def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None):
"""
Decorator for views that checks that the user is logged in, redirecting
to the log-in page if necessary.
"""
actual_decorator = request_passes_test(
lambda r: r.user.is_authenticated,
login_url=login_url,
redirect_field_name=redirect_field_name
)
if function:
return actual_decorator(function)
return actual_decorator
It is much simpler to change user to request.user rather than writing a custom request_passes_test function in every project that anyone wants to use it, and also it is more generic while user_passes_test is much more specific for certain use cases. There are some use cases where having the request variable instead of the user can be much more useful, for example if you want to use the Django message framework to send an error message when certain user does not pass a test. Does it make sense that there is no option to show a message to the user when they fail a test and redirect them to login without showing them any information?
In my current project I already have created my own request_passes_test decorator, but honestly I think more people would benefit from having this decorator in the source code (at least +30 people according to this post).
I hope more people can participate on this topic and give their opinion.
Thanks again for your time.
Best regards,
Iago.