Opened 10 years ago
Closed 10 years ago
#24276 closed Bug (wontfix)
django.contrib.auth.decorators.user_passes_test doesn't pass *args and *kwargs to resolve_url
Reported by: | rubengrill | Owned by: | nobody |
---|---|---|---|
Component: | contrib.auth | Version: | 1.7 |
Severity: | Normal | Keywords: | login_url resolve_url login_required user_passes_test |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
When using the decorator django.contrib.auth.decorators.user_passes_test or dependent decorators login_required and permission_required, the given login_url can't be reversed when the url contains at least one parameter, because when reverse_url is called, the *args and *kwargs parameters are not passed.
urlpatterns = patterns('', url(r'^(?P<conference>[^/]+)/', include(patterns('', url(r'^$', conference_root, name='conference_root'), url(r'^admin/$', conference_admin, name='conference_admin'), ))) ) ... @login_required(login_url='conference:conference_root') def conference_admin(request, conference): return render(request, 'conference/admin.html', {'conference': conference})
Reverse for 'conference_root' with arguments '()' and keyword arguments '{}' not found. 1 pattern(s) tried: ['(?P<conference>[^/]+)/$']
The *args and *kwargs parameters should be passed to resolve_url:
def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME): """ Decorator for views that checks that the user passes the given test, redirecting to the log-in page if necessary. The test should be a callable that takes the user object and returns True if the user passes. """ def decorator(view_func): @wraps(view_func, assigned=available_attrs(view_func)) def _wrapped_view(request, *args, **kwargs): if test_func(request.user): return view_func(request, *args, **kwargs) path = request.build_absolute_uri() # # resolved_login_url = resolve_url(login_url or settings.LOGIN_URL) # resolved_login_url = resolve_url(login_url or settings.LOGIN_URL, *args, **kwargs) # 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
Attachments (1)
Change History (3)
comment:1 by , 10 years ago
Easy pickings: | unset |
---|
by , 10 years ago
Attachment: | 24276-test.diff added |
---|
comment:2 by , 10 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
Please reopen if you can make a reply, thanks.
Note:
See TracTickets
for help on using tickets.
I think there is a problem with your approach and that is that if I use the decorator on a page with some capture parameters but the login page doesn't use those same parameters,
resolve_url()
won't work. I'm attaching a modification to one of Django's current tests that demonstrates the issue. I'll leave the ticket open if you want to think about other solutions, but it might be easiest for you to use a custom decorator for your use case.