it-swarm.dev

Django sınıfı temelli görünümlerde allow_required dekoratörleri nasıl kullanılır

Yeni CBV'lerin nasıl çalıştığını anlamakta biraz sıkıntı yaşıyorum. Sorum şu: Tüm görüşlerde ve bazılarında belirli izinlerde oturum açmam gerekiyor. İşlev tabanlı görünümlerde bunu @permission_required () ve görünümdeki login_required özniteliği ile yaparım, ancak bunu yeni görünümlerde nasıl yapacağımı bilmiyorum. Django belgelerinde bunu açıklayan bir kısım var mı? Hiçbir şey bulamadım. Kodumda yanlış olan ne?

@Method_decorator'ı kullanmaya çalıştım, fakat " TypeError 'de/spaces/prueba/_wrapped_view () en az 1 argüman alır (0 verilen) "

İşte kod (GPL):

from Django.utils.decorators import method_decorator
from Django.contrib.auth.decorators import login_required, permission_required

class ViewSpaceIndex(DetailView):

    """
    Show the index page of a space. Get various extra contexts to get the
    information for that space.

    The get_object method searches in the user 'spaces' field if the current
    space is allowed, if not, he is redirected to a 'nor allowed' page. 
    """
    context_object_name = 'get_place'
    template_name = 'spaces/space_index.html'

    @method_decorator(login_required)
    def get_object(self):
        space_name = self.kwargs['space_name']

        for i in self.request.user.profile.spaces.all():
            if i.url == space_name:
                return get_object_or_404(Space, url = space_name)

        self.template_name = 'not_allowed.html'
        return get_object_or_404(Space, url = space_name)

    # Get extra context data
    def get_context_data(self, **kwargs):
        context = super(ViewSpaceIndex, self).get_context_data(**kwargs)
        place = get_object_or_404(Space, url=self.kwargs['space_name'])
        context['entities'] = Entity.objects.filter(space=place.id)
        context['documents'] = Document.objects.filter(space=place.id)
        context['proposals'] = Proposal.objects.filter(space=place.id).order_by('-pub_date')
        context['publication'] = Post.objects.filter(post_space=place.id).order_by('-post_pubdate')
        return context
136
Oscar Carballal

CBV belgeleri 'de listelenen birkaç strateji vardır:

  1. Dekoratörü urls.py rotanıza ekleyin , örneğin, login_required(ViewSpaceIndex.as_view(..)) 

  2. CBV'niz dispatch yöntemini method_decorator ile dekore edin örn.,

    from Django.utils.decorators import method_decorator
    
    @method_decorator(login_required, name='dispatch')
    class ViewSpaceIndex(TemplateView):
        template_name = 'secret.html'
    

    Django 1.9'dan önce sınıfta method_decorator kullanamazsınız, bu yüzden dispatch yöntemini geçersiz kılmanız gerekir: 

    class ViewSpaceIndex(TemplateView):
    
        @method_decorator(login_required)
        def dispatch(self, *args, **kwargs):
            return super(ViewSpaceIndex, self).dispatch(*args, **kwargs)
    
  3. Django 1.9+ sürümünde mevcut olan Django.contrib.auth.mixins.LoginRequiredMixin gibi erişim karışımlarını kullanın ve buradaki diğer cevaplarda belirtildiği gibi:

    from Django.contrib.auth.mixins import LoginRequiredMixin
    
    class MyView(LoginRequiredMixin, View):
    
        login_url = '/login/'
        redirect_field_name = 'redirect_to'
    

Bir TypeError almanızın nedeni dokümanda açıklanmıştır:

Not: method_decorator, * args ve ** kwargs'ı sınıftaki dekore edilmiş yönteme parametre olarak geçirir. Eğer yönteminiz uyumlu bir parametre setini kabul etmiyorsa, bir TypeError istisnası oluşturacaktır.

170
A Lee

İşte yaklaşımım, korunan bir karışım oluşturuyorum (bu karışım kitaplığımda tutulur):

from Django.contrib.auth.decorators import login_required
from Django.utils.decorators import method_decorator

class LoginRequiredMixin(object):
    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
        return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)

Bir görüntünün korunmasını istediğiniz zaman sadece uygun karışımı ekleyin:

class SomeProtectedViewView(LoginRequiredMixin, TemplateView):
    template_name = 'index.html'

Sadece karışımınızın ilk olduğundan emin olun.

Güncelleme: Bunu 2011'de geri yolladım, 1.9 sürümünden itibaren Django şimdi bu ve diğer faydalı karışımları (AccessMixin, PermissionRequiredMixin, UserPassesTestMixin) standart olarak içeriyor!

114
Gert Steyn

İşte sınıf tabanlı dekoratörleri kullanarak bir alternatif:

from Django.utils.decorators import method_decorator

def class_view_decorator(function_decorator):
    """Convert a function based decorator into a class based decorator usable
    on class based Views.

    Can't subclass the `View` as it breaks inheritance (super in particular),
    so we monkey-patch instead.
    """

    def simple_decorator(View):
        View.dispatch = method_decorator(function_decorator)(View.dispatch)
        return View

    return simple_decorator

Bu daha sonra sadece böyle kullanılabilir:

@class_view_decorator(login_required)
class MyView(View):
    # this view now decorated
45
mjtamlyn

Bu iş parçacığının biraz tarihli olduğunu biliyorum, ama işte yine de iki sentim.

aşağıdaki kodla:

from Django.utils.decorators import method_decorator
from inspect import isfunction

class _cbv_decorate(object):
    def __init__(self, dec):
        self.dec = method_decorator(dec)

    def __call__(self, obj):
        obj.dispatch = self.dec(obj.dispatch)
        return obj

def patch_view_decorator(dec):
    def _conditional(view):
        if isfunction(view):
            return dec(view)

        return _cbv_decorate(dec)(view)

    return _conditional

şimdi bir dekoratör yama için bir yol var, bu yüzden çok işlevli olacak. Bu, normal görünüm dekoratörüne uygulandığında aşağıdaki gibi olduğu anlamına gelir:

login_required = patch_view_decorator(login_required)

bu dekoratör asıl amaçlandığı gibi kullanıldığında yine de çalışacaktır:

@login_required
def foo(request):
    return HttpResponse('bar')

ancak bu şekilde kullanıldığında da düzgün çalışacaktır:

@login_required
class FooView(DetailView):
    model = Foo

Bu gerçek dünyadan bir örnek de dahil olmak üzere son zamanlarda karşılaştığım birkaç durumda iyi çalışıyor gibi görünüyor:

@patch_view_decorator
def ajax_view(view):
    def _inner(request, *args, **kwargs):
        if request.is_ajax():
            return view(request, *args, **kwargs)
        else:
            raise Http404

    return _inner

Ajax_view işlevi, (işlev tabanlı) bir görünümü değiştirmek için yazılmıştır, böylece bu görünüm ajax olmayan bir çağrı tarafından ziyaret edildiğinde 404 hatası oluşturur. Sadece yama işlevini bir dekoratör olarak uygulayarak, bu dekoratörün tümü sınıf temelli görünümlerde de çalışacak şekilde ayarlanmıştır.

14
mephisto

Django> = 1.9 kullananlar için zaten AccessMixin , LoginRequiredMixin , PermissionRequiredMixin ve UserPassesTestMixin / olarak Django.contrib.auth.mixins içine dahil edilmiştir.

Yani, LoginRequired CBV'ye başvurmak için (örneğin, DetailView):

from Django.contrib.auth.mixins import LoginRequiredMixin
from Django.views.generic.detail import DetailView


class ViewSpaceIndex(LoginRequiredMixin, DetailView):
    model = Space
    template_name = 'spaces/space_index.html'
    login_url = '/login/'
    redirect_field_name = 'redirect_to'

Ayrıca GCBV Mixin siparişi akılda tutulmalıdır: Mixinssol tarafına gitmeli ve temel görünüm sınıfı sağ tarafına gitmelidir . Siparişin farklı olması durumunda, kırılmayan ve öngörülemeyen sonuçlar alabilirsiniz.

13
vishes_shell

Django Braces kullanın. Kolayca kullanılabilen birçok faydalı karışım sağlar. Çok güzel doktorları var. Denemek. 

Özel karışımlarınızı bile oluşturabilirsiniz.

http://Django-braces.readthedocs.org/en/v1.4.0/

Örnek kod:

from Django.views.generic import TemplateView

from braces.views import LoginRequiredMixin


class SomeSecretView(LoginRequiredMixin, TemplateView):
    template_name = "path/to/template.html"

    #optional
    login_url = "/signup/"
    redirect_field_name = "hollaback"
    raise_exception = True

    def get(self, request):
        return self.render_to_response({})
4
shap4th

Sayfaların çoğunun kullanıcının oturum açmasını gerektirdiği bir sitese, özellikle işaretli olanların hepsinde hariç oturumlarına giriş yapmak için ara katman kullanabilirsiniz.

Django Öncesi 1.10 middleware.py:

from Django.contrib.auth.decorators import login_required
from Django.conf import settings

EXEMPT_URL_PREFIXES = getattr(settings, 'LOGIN_EXEMPT_URL_PREFIXES', ())

class LoginRequiredMiddleware(object):
    def process_view(self, request, view_func, view_args, view_kwargs):
        path = request.path
        for exempt_url_prefix in EXEMPT_URL_PREFIXES:
            if path.startswith(exempt_url_prefix):
                return None
        is_login_required = getattr(view_func, 'login_required', True)
        if not is_login_required:
            return None
        return login_required(view_func)(request, *view_args, **view_kwargs) 

views.py:

def public(request, *args, **kwargs):
    ...
public.login_required = False

class PublicView(View):
    ...
public_view = PublicView.as_view()
public_view.login_required = False

Sarmak istemediğiniz üçüncü taraf görünümleri ayarlarda istisna edilebilir:

settings.py:

LOGIN_EXEMPT_URL_PREFIXES = ('/login/', '/reset_password/')
4
kaleissin

Kodumda bu adaptörü üye işlevlerini üye olmayan bir işleve uyarlamak için yazdım:

from functools import wraps


def method_decorator_adaptor(adapt_to, *decorator_args, **decorator_kwargs):
    def decorator_outer(func):
        @wraps(func)
        def decorator(self, *args, **kwargs):
            @adapt_to(*decorator_args, **decorator_kwargs)
            def adaptor(*args, **kwargs):
                return func(self, *args, **kwargs)
            return adaptor(*args, **kwargs)
        return decorator
    return decorator_outer

Basitçe bu şekilde kullanabilirsiniz:

from Django.http import HttpResponse
from Django.views.generic import View
from Django.contrib.auth.decorators import permission_required
from some.where import method_decorator_adaptor


class MyView(View):
    @method_decorator_adaptor(permission_required, 'someapp.somepermission')
    def get(self, request):
        # <view logic>
        return HttpResponse('result')
3
rabbit.aaron

Bu, Django> 1.9 ile PermissionRequiredMixin ve LoginRequiredMixin desteği ile geliyor. 

Sadece auth adresinden içe aktar 

views.py

from Django.contrib.auth.mixins import LoginRequiredMixin

class YourListView(LoginRequiredMixin, Views):
    pass

Daha fazla ayrıntı için Django'da Yetkilendirme

1
Amar

Çeşitli izin testleri gerektiren bir proje yapıyorsanız, bu dersi miras alabilirsiniz.

from Django.contrib.auth.decorators import login_required
from Django.contrib.auth.decorators import user_passes_test
from Django.views.generic import View
from Django.utils.decorators import method_decorator



class UserPassesTest(View):

    '''
    Abstract base class for all views which require permission check.
    '''


    requires_login = True
    requires_superuser = False
    login_url = '/login/'

    permission_checker = None
    # Pass your custom decorator to the 'permission_checker'
    # If you have a custom permission test


    @method_decorator(self.get_permission())
    def dispatch(self, *args, **kwargs):
        return super(UserPassesTest, self).dispatch(*args, **kwargs)


    def get_permission(self):

        '''
        Returns the decorator for permission check
        '''

        if self.permission_checker:
            return self.permission_checker

        if requires_superuser and not self.requires_login:
            raise RuntimeError((
                'You have assigned requires_login as False'
                'and requires_superuser as True.'
                "  Don't do that!"
            ))

        Elif requires_login and not requires_superuser:
            return login_required(login_url=self.login_url)

        Elif requires_superuser:
            return user_passes_test(lambda u:u.is_superuser,
                                    login_url=self.login_url)

        else:
            return user_passes_test(lambda u:True)
0

Josh'un çözümüne dayanarak bu düzeltmeyi yaptım.

class LoginRequiredMixin(object):

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

Örnek kullanım:

class EventsListView(LoginRequiredMixin, ListView):

    template_name = "events/list_events.html"
    model = Event
0
Ramast