1. ホーム
  2. django

[解決済み] django のクラスベースのビューで permission_required デコレータを使用する方法

2022-05-02 15:25:25

質問

新しいCBVの仕組みを理解するのに少し苦労しています。私の質問はこれです、私はすべてのビューでログインを要求する必要があり、そのうちのいくつかでは、特定のパーミッションが必要です。関数ベースのビューでは、@permission_required()とビューのlogin_required属性でそれを行いますが、新しいビューでこれを行う方法がわかりません。django のドキュメントに、これを説明するセクションがありますか?私は何も見つけられませんでした。私のコードのどこがおかしいのでしょうか?

method_decorator を使おうとしましたが、 " と返されました。 TypeError at /spaces/prueba/ _wrapped_view() takes at least 1 argument (0 given) "

以下はそのコードです(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

解決方法は?

には、いくつかの戦略が記載されています。 CBVのドキュメント :

でインスタンス化する際に、ビューを装飾します。 urls.py ( ドキュメント )

urlpatterns = [
    path('view/',login_required(ViewSpaceIndex.as_view(..)),
    ...
]

このデコレータはインスタンス単位で適用されるため、インスタンスごとにデコレータを追加したり削除したりすることができます。 urls.py ルートで使用できます。

ビューのすべてのインスタンスがラップされるように、クラスを装飾する ( ドキュメント )

2つの方法があるんだ

  1. 適用する method_decorator をCBVのディスパッチメソッドに追加する 例です。

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

Django < 1.9 を使っている場合 (サポートが終了しているので、使わない方が良いでしょう) は method_decorator をオーバーライドする必要があります。 dispatch メソッドを手動で実行します。

    class ViewSpaceIndex(TemplateView):

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

  1. のようなミキシンを使用します。 django.contrib.auth.mixins.LoginRequiredMixin は、ここの他の回答でよく説明されています。

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

mixin クラスを継承リストの最初に配置するようにします (Python の メソッド解決順序アルゴリズム が正しいものを選ぶ)。

が表示されるのは TypeError は、docsに説明があります。

注意 method_decorator は、装飾されたメソッドのパラメータとして *args と **kwargs をクラス上に渡します。もしメソッドが互換性のあるパラメータを受け入れない場合、例外 TypeError が発生します。