Comment exiger une connexion pour Django Generic Views?

87

Je souhaite restreindre l'accès aux URL gérées par Django Generic Views.

Pour mes vues, je sais que le login_requireddécorateur fait le travail. Créer / Supprimer / Mettre à jour les vues génériques prennent également l' login_requiredargument, mais je n'ai pas trouvé de moyen de le faire pour d'autres vues génériques.

hamdiakoguz
la source

Réponses:

104

Pour Django <1.5, vous pouvez ajouter un décorateur en enveloppant la fonction dans vos urls, ce qui vous permet d'encapsuler les vues génériques:

from django.contrib.auth.decorators import login_required
from django.views.generic.simple import direct_to_template
urlpatterns = patterns('',
    (r'^foo/$', login_required(direct_to_template), {'template': 'foo_index.html'}),
    )

Les vues génériques basées sur les fonctions sont obsolètes dans Django 1.4 et ont été supprimées dans Django 1.5. Mais le même principe s'applique, enveloppez simplement la fonction de vue de la vue basée sur la classe avec le login_requireddécorateur:

login_required(TemplateView.as_view(template_name='foo_index.html'))
Will Hardy
la source
Voici comment spécifier login_url login_required (TemplateView.as_view (template_name = 'foo_index.html'))
Saisiva A
101

Django 1.9 ou utiliser des accolades django

Django 1.9 a introduit un LoginRequiredMixin qui est utilisé ainsi:

from django.contrib.auth.mixins import LoginRequiredMixin

class MyView(LoginRequiredMixin, View):
    login_url = '/login/'
    redirect_field_name = 'redirect_to'

Si vous utilisez une ancienne version de django, vous pouvez utiliser à peu près le même mixin de django-braces - la version de Django était basée sur la version de django-braces. django-braces 1.4.x supporte toujours Django 1.4 afin que vous puissiez l'utiliser avec des versions assez anciennes.

Méthodes plus anciennes

J'ai trouvé cette question en cherchant sur Google comment décorer les vues basées sur les classes, alors pour ajouter la réponse à cela:

Ceci est couvert dans la section de documentation sur la décoration des vues basées sur les classes . Il y a le urls.pywrapper, ou vous pouvez appliquer le décorateur à la dispatch()méthode. Exemples tirés de la documentation:

Décorer dans la conf URL

from django.contrib.auth.decorators import login_required, permission_required
from django.views.generic import TemplateView

from .views import VoteView

urlpatterns = patterns('',
    (r'^about/', login_required(TemplateView.as_view(template_name="secret.html"))),
    (r'^vote/', permission_required('polls.can_vote')(VoteView.as_view())),
)

Décorer la classe

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

class ProtectedView(TemplateView):
    template_name = 'secret.html'

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(ProtectedView, self).dispatch(*args, **kwargs)

Voir la documentation liée à ci-dessus pour plus de détails.

Hamish Downer
la source
IMPRESSIONNANT! mais j'ai fait une classe simple avec seulement la def dispatchméthode comme sous-classe de View. Maintenant, je peux simplement faire quelque chose comme ceci:class ProtectedTemplateView(TemplateView, ProtectedView): pass
WBAR
si je ne définirai pas le login_url mais que je le définirai sur settings.py, sera-t-il redirigé vers celui-ci par défaut?
Marat Mkitaryan
38

Les vues génériques sont passées des fonctions aux objets avec la version 1.3 de Django. En tant que tel, il y a un léger changement nécessaire pour que les réponses de Will McCutchen et Will Hardy fonctionnent avec la version 1.3:

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

urlpatterns = patterns('',
    (r'^foo/$', login_required(TemplateView.as_view(template_name='foo_index.html'))),
)

La documentation décrit également comment procéder.

Brian Fisher
la source
2
S'il vous plaît, lecteur, prenez en compte cette réponse car le temps passe et le logiciel évolue. La première solution ne fonctionnait pas pour moi.
n3storm
12

Si vous ne voulez pas écrire votre propre wrapper léger autour des vues génériques en question (comme Aamir l'a suggéré), vous pouvez également faire quelque chose comme ceci dans votre urls.pyfichier:

from django.conf.urls.defaults import *

# Directly import whatever generic views you're using and the login_required
# decorator
from django.views.generic.simple import direct_to_template
from django.contrib.auth.decorators import login_required

# In your urlpatterns, wrap the generic view with the decorator
urlpatterns = patterns('',
    (r'', login_required(direct_to_template), {'template': 'index.html'}),
    # etc
)
Will McCutchen
la source
8

Pour django 1.11, vous pouvez utiliser LoginRequiredMixin pour les vues basées sur les classes

dans le fichier de paramètres, vous devez ajouter

LOGIN_URL="/login/"

dans votre views.py

from django.contrib.auth.mixins import LoginRequiredMixin

class RestaurantLocationCreateView(LoginRequiredMixin,CreateView):
    ....
Natiq Vahabov
la source
8

Une autre façon d'y parvenir est ci-dessous, j'aime que cela soit assez similaire à la façon dont c'est fait avec des vues basées sur les fonctions et ne nécessite pas de modification urls.pyou de remplacement dispatch:

@method_decorator(login_required, name='dispatch')
class YourGenericViewSubclass(TemplateView):
    #
    # View methods
    #
Şafak Gezer
la source
3

Je voulais un moyen réutilisable d'exiger l'authentification sur de nombreuses vues dérivées de vues génériques. J'ai créé une fonction de répartition de remplacement que je peux ajouter à ma classe de vue de la même manière que pour les autres déclarations.

class Index(generic.ListView):
    model = models.HomePage
    dispatch = auth.dispatch

auth.dispatch est l'endroit où nous faisons le travail:

def dispatch(self, request, *args, **kw):
    """Mix-in for generic views"""
    if userSession(request):
        return  super(self.__class__, self).dispatch(request, *args, **kw)

    # auth failed, return login screen
    response = user(request)
    response.set_cookie('afterauth', value=request.path_info)
    return response
julien
la source
3

Dans Django => 3.0, cela devient assez simple:

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(login_url='/login/'), name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

pour référence: https://docs.djangoproject.com/en/3.0/topics/class-based-views/intro/#decorating-the-class

bernardhilbink87
la source
1

Utilisez le suivant:

from django.contrib.auth.decorators import login_required

@login_required
def your_view():
    # your code here
Aamir Hussain
la source
5
Sur la base de la date de la question, je suppose que l'OP demande une solution pour les vues génériques basées sur les classes de django ... pas les vues basées sur les fonctions.
Dolph
0

Ce qui suit pourrait résoudre ce problème.

// in views.py:
class LoginAuthenAJAX(View):
    def dispatch(self, request, *args, **kwargs):
        if request.user.is_authenticated:
            jsonr = json.dumps({'authenticated': True})
        else:
            jsonr = json.dumps({'authenticated': False})
        return HttpResponse(jsonr, content_type='application/json')

// in urls.py
    path('login_auth', views.LoginAuthenAJAX.as_view(), name="user_verify"),

//in xxx.html
<script src = “{% static “xxx/script.js” %}” 
var login_auth_link = “{%  url ‘user_verify’ %}”
</script>

// in script.js
        $.get(login_auth_link, {
            'csrfmiddlewaretoken' : csrf_token,
            },
            function(ret){
                if (ret.authenticated == false) {
                    window.location.pathname="/accounts/login/"
                }
                $("#message").html(ret.result);
            }
        )
Shuyuan Yu
la source