6

According to one of the comments in https://stackoverflow.com/a/8715790/210481, which I agree with, we should avoid multiple decorators if one depends on the other.

So, in the example, if we have a decorator "active_required" for active users, we should not have to use both active_required and login_required on the same view.

We should have "login_required" decorator "called" somehow inside the "active_required" one.

Is it possible to do it with the standard "login_required" decorator that comes with django?

My requirements are: 1) if the user is not authenticated, I should redirect him to LOGIN_URL 2) if the user is authenticated (passed login_required), but is not active, I should redirect him to a page to "re-activate" his account 3) if the user is authenticated and active, the user can access the view

Thanks in advance

Community
  • 1
  • 1
duduklein
  • 10,014
  • 11
  • 44
  • 55
  • since you want different behaviours in the 3 possible cases, having two decorators seems fine – second Mar 01 '12 at 19:11
  • As I understard you want to use only one decorator instead of two that does two different tests? – sergzach Mar 01 '12 at 19:27
  • I want 2 different behaviors but one depends necessarily on the other. @ChrisPratt, I was looking at your comment, when I thought of this. The standard login function does not check for "active" flag, only if username and password match. I can think of other examples: In my site, users can create lists and only the owner of the list can edit the list, so I need to check if the user is logged in and if it's the owner of the list. This is just another example. – duduklein Mar 01 '12 at 20:42

1 Answers1

8

When thinking about your question, I found it easier to create a simple active_required decorator first. This is very easy, because we can use the the user_passes_test function in django.contrib.auth.decorators.

The question then changes to "how do I combine the login_required and active_required into one decorator?". We need to define a function which:

  1. takes a view function as it's argument
  2. applies both decorators to it to create a new view function
  3. returns the new view function

Putting it all together, you have the following:

from django.contrib.auth.decorators import user_passes_test, login_required

active_required = user_passes_test(lambda u: u.is_active, login_url=REACTIVATE_URL)

def active_and_login_required(view_func):
    decorated_view_func = login_required(active_required(view_func))
    return decorated_view_func
Alasdair
  • 298,606
  • 55
  • 578
  • 516