Bagaimana cara memerlukan login untuk Django Generic Views?

88

Saya ingin membatasi akses ke URL yang ditangani oleh Django Generic Views.

Untuk Tampilan saya, saya tahu bahwa login_requireddekorator melakukan pekerjaan itu. Juga Buat / Hapus / Perbarui Tampilan Generik mengambil login_requiredargumen, tetapi saya tidak dapat menemukan cara untuk melakukan ini untuk Tampilan Generik lainnya.

hamdiakoguz
sumber

Jawaban:

104

Untuk Django <1.5, Anda bisa menambahkan dekorator dengan membungkus fungsi di url Anda, yang memperbolehkan Anda untuk membungkus tampilan umum:

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

Tampilan umum berbasis fungsi tidak digunakan lagi di Django 1.4 dan dihapus di Django 1.5. Tetapi prinsip yang sama berlaku, cukup bungkus fungsi tampilan dari tampilan berbasis kelas dengan login_requireddekorator:

login_required(TemplateView.as_view(template_name='foo_index.html'))
Will Hardy
sumber
Di sini cara menentukan login_url login_required (TemplateView.as_view (template_name = 'foo_index.html'))
Saisiva A
103

Django> = 1.9 atau menggunakan django-braces

Django 1.9 telah memperkenalkan sebuah LoginRequiredMixin yang digunakan sebagai berikut:

from django.contrib.auth.mixins import LoginRequiredMixin

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

Jika Anda menggunakan versi lama dari django Anda dapat menggunakan campuran yang hampir sama dari django-braces - versi Django didasarkan pada versi django-braces. django-braces 1.4.x masih mendukung Django 1.4 sehingga Anda dapat menggunakannya dengan versi lama yang cantik.

Metode Lama

Saya menemukan pertanyaan ini saat mencari di Google tentang cara menghias tampilan berbasis kelas, jadi untuk menambahkan jawabannya:

Ini tercakup dalam bagian dokumentasi tentang mendekorasi tampilan berbasis kelas . Ada urls.pypembungkusnya, atau Anda dapat menerapkan dekorator ke dispatch()metode. Contoh dari dokumentasi:

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

Mendekorasi kelas

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)

Lihat dokumentasi yang ditautkan di atas untuk lebih jelasnya.

Hamish Downer
sumber
LUAR BIASA! tetapi saya membuat kelas sederhana dengan hanya def dispatchmetode sebagai subkelas View. Sekarang saya bisa membuat sesuatu seperti ini:class ProtectedTemplateView(TemplateView, ProtectedView): pass
WBAR
jika saya tidak akan menyetel login_url tetapi menyetelnya di settings.py akankah dialihkan ke ini secara default?
Marat Mkhitaryan
38

Tampilan umum telah berubah dari fungsi ke objek dengan versi 1.3 dari Django. Karena itu, ada sedikit perubahan yang diperlukan agar jawaban Will McCutchen dan Will Hardy dapat berfungsi dengan versi 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'))),
)

Juga dokumentasi menjelaskan bagaimana melakukan ini juga.

Brian Fisher
sumber
2
Tolong, pembaca, pertimbangkan jawaban ini karena waktu berlalu dan perangkat lunak berkembang. Solusi pertama tidak berhasil untuk saya.
n3storm
12

Jika Anda tidak ingin menulis pembungkus tipis Anda sendiri di sekitar tampilan umum yang dimaksud (seperti yang disarankan Aamir), Anda juga dapat melakukan sesuatu seperti ini di urls.pyfile Anda :

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
sumber
8

Untuk django 1.11, Anda dapat menggunakan LoginRequiredMixin untuk Tampilan berbasis Kelas

di file pengaturan yang harus Anda tambahkan

LOGIN_URL="/login/"

di views.py Anda

from django.contrib.auth.mixins import LoginRequiredMixin

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

Cara lain untuk mencapai ini adalah di bawah, saya suka itu sangat mirip dengan cara melakukannya dengan tampilan berbasis fungsi dan tidak memerlukan modifikasi urls.pyatau penggantian dispatch:

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

Saya menginginkan cara yang dapat digunakan kembali untuk meminta otorisasi pada banyak tampilan yang berasal dari tampilan umum. Saya membuat fungsi pengiriman pengganti yang dapat saya tambahkan ke kelas tampilan saya dengan cara yang sama seperti deklarasi lainnya.

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

auth.dispatch adalah tempat kami melakukan pekerjaan:

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
Julian
sumber
3

Dalam Django => 3.0 ini menjadi sangat mudah:

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'

untuk referensi: https://docs.djangoproject.com/en/3.0/topics/class-based-views/intro/#decorating-the-class

bernardhilbink87
sumber
1

Gunakan yang berikut ini:

from django.contrib.auth.decorators import login_required

@login_required
def your_view():
    # your code here
Aamir Hussain
sumber
5
Berdasarkan tanggal pertanyaan, saya berasumsi OP meminta solusi untuk tampilan umum berbasis kelas django ... bukan tampilan berbasis fungsi.
Dolph
0

Berikut ini bisa menyelesaikan masalah ini.

// 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
sumber
0

Saya telah berjuang untuk menemukan jawaban untuk ini untuk waktu yang lama sampai saya menemukan solusi ini.

Dalam models.py do: from django.db import model

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

Dalam forms.py lakukan:

from django import forms
from .models import YourLoginModel

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

Dalam logika login 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})

Dalam tampilan aplikasi Anda ingin melakukan login_required pada 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')
George m
sumber