0

Django 1.9.6.

I want to absolutely disable the whole website from viewing by anonymous users. Anonymous users will always be redirected to login page.

I have created a general view. The problem is that subclasses of GeneralView may not just render a template but perform some calculations or just be of different kinds: DetailView, ListView etc.

class GeneralView(View):
    def get(self, request, template):
        if not request.user.is_authenticated() and request.user.is_active:            
            return redirect("auth_login")
        else:
            return render(request, template)

If I try to inherit, the code gets clumsy:

class HomePageView(GeneralView):
    def get(self, request, template):
        super().get(self, request)

Well, what can I do here? I get error message that my get method doesn't return HttpResponse.

I can rewrite get method of the superclass to return status code. Then check it in the subclass. But this seems to be garbage.

In other words I'm lost in clouds of inheritance. Could you give me a kick here how always to redirect anonymous users to login page, whereas let logged in users see everything.

Thank you in advance.

Michael
  • 4,273
  • 3
  • 40
  • 69
  • Possible duplicate of [Best way to make Django's login\_required the default](http://stackoverflow.com/questions/2164069/best-way-to-make-djangos-login-required-the-default) – Sayse Jun 02 '16 at 16:45

4 Answers4

2

You could use the UserPassesTestMixin for this.

from django.core.urlresolvers import reverse_lazy

class GeneralView(UserPassesTestMixin, View):

    def test_func(self):
        # I assume you missed out the brackets in your question and actually wanted 'if not (request.user.is_authenticated() and request.user.is_active)'
        return request.user.is_authenticated() and request.user.is_active

    login_url = reverse_lazy('auth_login')

The mixin overrides dispatch, so you won't have to call super() when you override get() in your view.

 class HomePageView(GeneralView):
     def get(self, request):
         ...
Alasdair
  • 298,606
  • 55
  • 578
  • 516
0

I think your error for get method not returning belongs to not putting a return statement. in fact, in get method of the child class you should do:

class HomePageView(GeneralView):
  def get(self, request, template):
      return super().get(self, request)

That should solve the error

Nikign
  • 379
  • 3
  • 9
  • Thank you for the comment. But I still can't catch the idea. Where is the business logic of HomePageView? It will just return what the superclass returns. I would like to keep in the superclass only checking for being logged in. In other words else condition should not be in the superclass at all. As it relates to the particular business logic of subclasses. – Michael Jun 02 '16 at 16:08
  • You can put the logic in another function and call it in the else of the superclass. Then you can simply override that function in each of the child classes. – Nikign Jun 02 '16 at 16:17
0

If you have lots of views and you do not want to touch any one you can just use Middleware for this issue. Try code below:


import traceback
from django.contrib.auth.decorators import login_required


class RejectAnonymousUsersMiddleware(object):

    def process_view(self, request, view_func, view_args, view_kwargs):
        current_route_name = resolve(request.path_info).url_name

        if current_route_name in settings.AUTH_EXEMPT_ROUTES:
            return

        if  request.user.is_authenticated:
            return

        return login_required(view_func)(request, *view_args, **view_kwargs)

Cautions:

  • You must add this middleware to the bottommost of middleware section of settings.py
  • You should put this variable in settings.py
    • AUTH_EXEMPT_ROUTES = ('register', 'login', 'forgot-password')
Ehsan Ahmadi
  • 1,382
  • 15
  • 16
0

New versions of Django provides the @login_required decorator. If an anonymous user tries to access the view, the system redirects to the login page.

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
   ...

It can be used in function views, as shown above, or generic views (using @method_decorator, usually in dispatch method)

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView

@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
   template_name = 'secret.html'
William
  • 331
  • 1
  • 3
  • 12