Private by default
On July 22, 2007 in
When most pages in a site require authentication, decorating all the views with @login_required can be annoying. You can reverse the default behavior by creating a custom middleware class:
import urllib
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.http import HttpResponseRedirect
def allow_anonymous(view_func):
view_func.allow_anonymous = True
return view_func
class RequireLogin:
def process_view(self, request, view_func, view_args, view_kwargs):
if request.path != settings.LOGIN_URL and \
not request.user.is_authenticated() and \
not getattr(view_func, 'allow_anonymous', False):
url = '%s?%s=%s' % (settings.LOGIN_URL, REDIRECT_FIELD_NAME, \
urllib.quote(request.get_full_path()))
return HttpResponseRedirect(url)
That’s an ugly block of code but it’s not too complex. allow_anonymous is a function decorator, like login_required. It just tags the function to tell the middleware that authentication isn’t required. The RequireLogin class verifies that the user is logged in. If not, and if the function is not decorated with allow_anonymous, it redirects to settings.LOGIN_URL.
So put that code in a file in your project – let’s say, yourproject/yourapp/middleware.py. Then open settings.py and add "yourproject.yourapp.middleware.RequireLogin" to
MIDDLEWARE_CLASSES. This tells Django about your new middleware class, and RequireLogin.process_view will be called any time a view is about to be rendered.
Now you can use it in your view:
views.pyfrom yourproject.yourapp.middleware import allow_anonymous
def some_private_view(request):
# won't be accessible unless user is logged in
return HttpResponse('Hello, user!')
@allow_anonymous
def some_public_view(request):
return HttpResponse('Hello, world!')
If all is working correctly, some_private_view should ask for a login, but some_public_view will allow viewing without it.
Update: I’ve updated the code to fix a bug when using django.contrib.auth.views.login for your login view. As you can’t mark this view function with
@allow_anonymous, it would infinitely redirect back to it. Oops! Thanks for pointing it out, Phil.
12 comments Add yours…