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
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):
...