Sophia111 Sophia111 - 1 year ago 47
Python Question

Differentiating unauthenticated users in custom decorator

Django beginner here.

I have been using the inbuilt

login_required
decorator. I want to override it for certain users who's referral urls match a certain pattern (e.g. all users originating from
/buy_and_sell/
).

My purpose is to show a special login page to just these users, and a generic one to everyone else.

I've been looking at various examples of writing custom decorators (e.g. here, here, here and here). But I find the definitions hard to grasp for a beginner. Can someone give me a layman's understanding (and preferably illustrative example) of how I can solve my problem?

Answer Source

There is user_passes_test decorator included in Django.You do not have to make your own decorator.

from django.contrib.auth.decorators import user_passes_test

def check_special_user(user):
    return user.filter(is_special=True)

# if not the special user it will redirect to another login url , otherwise process the view
@user_passes_test(check_special_user,login_url='/login/') 
def my_view(request):
   pass
    ...

Need Request in decorator

To do that make a clone version of user_passes_test in your project or app and make change as follow,

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):  # change this line to request instead of request.user
                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

change test_func(request.user) to test_func(request) and you will get whole request in your decorator function.

Edit: In url.py ,

url (
    r'^your-url$',
    user_passes_test(check_special_user, login_url='/login/')(
        my_view
    ),
    name='my_view'
)
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download