Come richiedere il login per Django Generic Views?


88

Voglio limitare l'accesso agli URL gestiti da Django Generic Views.

Per quanto mi riguarda, so che il login_requireddecoratore fa il lavoro. Anche Crea / Elimina / Aggiorna visualizzazioni generiche accetta l' login_requiredargomento, ma non sono riuscito a trovare un modo per farlo per altre visualizzazioni generiche.

Risposte:


104

Per Django <1.5, puoi aggiungere un decoratore avvolgendo la funzione nei tuoi URL, che ti permette di racchiudere le viste generiche:

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'}),
    )

Le viste generiche basate su funzioni sono deprecate in Django 1.4 e sono state rimosse in Django 1.5. Ma si applica lo stesso principio, basta avvolgere la funzione di visualizzazione della vista basata sulla classe con il login_requireddecoratore:

login_required(TemplateView.as_view(template_name='foo_index.html'))

Ecco come specificare login_url login_required (TemplateView.as_view (template_name = 'foo_index.html'))
Saisiva A

103

Django> = 1.9 o usando le parentesi graffe django

Django 1.9 ha introdotto un LoginRequiredMixin che viene utilizzato così:

from django.contrib.auth.mixins import LoginRequiredMixin

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

Se stai usando una versione precedente di django puoi usare più o meno lo stesso mixin di django-braces - la versione di Django era basata sulla versione di django-braces. django-braces 1.4.x supporta ancora Django 1.4 quindi puoi usarlo con versioni piuttosto vecchie.

Metodi più vecchi

Ho trovato questa domanda mentre cercavo su Google come decorare le viste basate sulla classe, quindi per aggiungere la risposta:

Questo è trattato nella sezione della documentazione sulla decorazione delle viste basate sulle classi . C'è l' urls.pyinvolucro, oppure puoi applicare il decoratore al filedispatch() metodo. Esempi dalla documentazione:

Decorare in URL conf

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())),
)

Decorare 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)

Vedere la documentazione collegata sopra per maggiori dettagli.


ECCEZIONALE! ma ho creato una classe semplice con il solo def dispatchmetodo come sottoclasse di View. Ora posso semplicemente fare qualcosa del genere:class ProtectedTemplateView(TemplateView, ProtectedView): pass
WBAR

se non imposto login_url ma lo imposto su settings.py verrà reindirizzato a questo per impostazione predefinita?
Marat Mkhitaryan

38

Le viste generiche sono cambiate da funzioni a oggetti con la versione 1.3 di Django. Pertanto, è necessario un leggero cambiamento affinché le risposte di Will McCutchen e Will Hardy funzionino con la versione 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'))),
)

Anche la documentazione descrive come eseguire questa operazione.


2
Per favore, lettore, prendi in considerazione questa risposta perché il tempo passa e il software si evolve. La prima soluzione non funzionava per me.
n3storm

12

Se non vuoi scrivere il tuo involucro sottile attorno alle viste generiche in questione (come suggerito da Aamir), puoi anche fare qualcosa di simile nel tuo urls.pyfile:

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
)

8

Per django 1.11, puoi usare LoginRequiredMixin per viste basate su classi

nel file delle impostazioni dovresti aggiungere

LOGIN_URL="/login/"

in your views.py

from django.contrib.auth.mixins import LoginRequiredMixin

class RestaurantLocationCreateView(LoginRequiredMixin,CreateView):
    ....

8

Un altro modo per ottenere ciò è di seguito, mi piace che sia abbastanza simile a come è fatto con le viste basate su funzioni e non richiede modifiche urls.pyo override dispatch:

@method_decorator(login_required, name='dispatch')
class YourGenericViewSubclass(TemplateView):
    #
    # View methods
    #

3

Volevo un modo riutilizzabile per richiedere l'autenticazione su molte viste derivate da viste generiche. Ho creato una funzione di invio sostitutivo che posso aggiungere alla mia classe di visualizzazione nello stesso modo delle altre dichiarazioni.

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

auth.dispatch è dove facciamo il lavoro:

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


1

Utilizza il seguente:

from django.contrib.auth.decorators import login_required

@login_required
def your_view():
    # your code here

5
In base alla data della domanda, presumo che l'OP stia chiedendo una soluzione per le viste generiche basate su classi di django ... non viste basate su funzioni.
Dolph

0

Quanto segue potrebbe risolvere questo problema.

// 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);
            }
        )

0

Ho lottato a lungo per trovare la risposta a questo problema finché non ho trovato questa soluzione.

In models.py fai: da django.db importa i modelli

class YourLoginModel:
      fullname = models.CharField(max_length=255, default='your_name', unique=True)
      email  = models.EmailField(max_length=255, unique=True)
      username = models.CharField(max_length=255, unique=True)
      password = models.CharField(max_length=255) #using werkzeug's 
                                                  #generate_password_hash on plaintext password before committing to database model

In forms.py fai:

from django import forms
from .models import YourLoginModel

class LoginForm(forms.ModelForm):
      class Meta:
            model = YourLoginModel
            fields = ('username', 'password')

Nella logica di accesso views.py:

def login(request):
    #login logic here
     # init empty form
    form = LoginForm()

    if request.method == 'POST':

        try:
            # peforms a Select query in db and gets user with log in username
            user_logging_in = User.objects.get(username=request.POST['username'])

            # assign user hash to var
            hash = user_logging_in.password

            # assign form str passs word to var
            password = request.POST['password']

        # if the user does not exist
        except ObjectDoesNotExist:
            html_response = 'User does not exists'
            return HttpResponse(html_response)

        # peform password and hash check
        if check_password_hash(hash, password):
 
            #using sessions cookies to know who we're interacting with
            request.session['username'] = request.POST['username']

            #set expiry date of the session
            request.session.set_expiry(0) # 0 means when the browser is closed

            return redirect('yourapp:home')
        else:
            return HttpResponse('password was incorrect')

    html = 'Login'
    return render(request, 'login.html', {'form': form})

Nella visualizzazione app si desidera eseguire login_required su do

from django.views.generic import TemplateView

class yourTemplateView(TemplateView):
      template_name = 'your_template.html'
      def dispatch(self, request, *args, **kwrags):
           if not request.session.has_key('username'):
              #return HttpResponse('not logged in')
              return redirect('yourapp:login.html')
           else:
              return render(request, 'your_view.html')
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.