What is the opposite of @login_required decorator for Django views?

后端 未结 6 2065
耶瑟儿~
耶瑟儿~ 2020-12-29 09:37

If I want to make sure that a view is listed as having public access, is there a decorator equivalent to @public_access which would be the opposite of @login_required and ma

6条回答
  •  一整个雨季
    2020-12-29 10:04

    I use django-decorator-include to use the login_required decorator to secure an entire app, rather than one view at a time. My app's main urls.py looks like this:

    path('my_secret_app/', decorator_include(login_required, ('my_secret_app.urls', 'my_secret_app'))),
    

    This works great, except for when one of my apps has one view which needs to be public.

    To get around this, I wrote my own login_required and login_not_required. My login_required is based on django's django.contrib.auth.decorators.login_required, but is slightly modified to actually care when a view is marked as not requiring login.

    My project is called mysite.

    My app is called my_secret_app.

    My public view within my_secret_app is called MyPublicView.

    My entire solution looks like this:

    mysite/lib.py

    from django.contrib.auth import REDIRECT_FIELD_NAME
    from django.contrib.auth.decorators import user_passes_test
    
    # A copy of django.contrib.auth.decorators.login_required that looks for login_not_required attr
    def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None):
        actual_decorator = user_passes_test(
            lambda u: u.is_authenticated,
            login_url=login_url,
            redirect_field_name=redirect_field_name
        )
    
        if function:
            login_req = getattr(function, "login_required", True)
    
            if login_req:
                return actual_decorator(function)
            else:
                return function
        else:
            return actual_decorator
    
    # Decorator to mark a view as not requiring login to access
    def login_not_required(f):
        f.login_required = False
        return f
    

    mysite/urls.py

    from .lib import login_required
    path('my_secret_app/', decorator_include(login_required, ('my_secret_app.urls', 'my_secret_app'))),
    

    my_secret_app/views.py:

    from django.utils.decorators import method_decorator
    from mysite.lib import login_not_required
    
    class MyPublicView(View):
        @method_decorator(login_not_required)
        def dispatch(self, request, *args, **kwargs):
            return super().dispatch(request, *args, **kwargs)
    
        def get(self, request):
            ...
    
        def post(self, request, *args, **kwargs):
            ...
    

    You should be able to do the same thing no matter if you're subclassing View, ListView, CreateView, UpdateView, TemplateView, or any of the other ones. It should also work if you're using a function as your view, though I haven't tried it:

    @login_not_required
    def MyPublicView(request):
        ...
    

提交回复
热议问题