通常、クラスベースビューのdispatch
メソッドを使用して、初期変数を設定したり、ユーザーの権限に基づいてロジックを追加したりします。
例えば、
from Django.views.generic import FormView
from braces.views import LoginRequiredMixin
class GenerateReportView(LoginRequiredMixin, FormView):
template_name = 'reporting/reporting_form.html'
form_class = ReportForm
def get_form(self, form_class):
form = form_class(**self.get_form_kwargs())
if not self.request.user.is_superuser:
form.fields['report_type'].choices = [
choice for choice in form.fields['report_type'].choices
if choice[0] != INVOICE_REPORT
]
return form
期待どおりに動作します。匿名ユーザーがページにアクセスすると、 LoginRequiredMixin のdispatch
メソッドが呼び出され、ユーザーがログインページ。
しかし、このビューにいくつかの権限を追加したり、いくつかの初期変数を設定したりする場合は、たとえば、
class GenerateReportView(LoginRequiredMixin, FormView):
def dispatch(self, *args, **kwargs):
if not (
self.request.user.is_superuser or
self.request.user.is_manager
):
raise Http404
return super(GenerateReportView, self).dispatch(*args, **kwargs)
ビューが継承するミックスインのdispatch
メソッドがまだ呼び出されていないため、機能しない場合があります。したがって、たとえば、ユーザーの権限を要求できるようにするには、LoginRequiredMixin
から検証を繰り返す必要があります。
class GenerateReportView(LoginRequiredMixin, FormView):
def dispatch(self, *args, **kwargs):
if self.request.user.is_authenticated() and not (
self.request.user.is_superuser or
self.request.user.is_manager
):
raise Http404
return super(GenerateReportView, self).dispatch(*args, **kwargs)
この例は単純ですが、ミックスインにはさらに複雑なロジックが含まれている場合があります。これは、権限を確認し、いくつかの計算を行い、それをクラス属性に格納するなどです。
今のところ、(上記の例のように)ミックスインからコードをコピーするか、ビューのdispatch
メソッドから別のミックスインにコードをコピーし、最初のコードの後に継承して実行することで解決します順序(この新しいミックスインは1つのビューでのみ使用されるため、それほどきれいではありません)。
適切な方法があるので、このような問題を解決しますか?
すべての権限をチェックするカスタムクラスを作成します
from Django.views.generic import FormView
from braces.views import AccessMixin
class SuperOrManagerPermissionsMixin(AccessMixin):
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated():
return self.handle_no_permission(request)
if self.user_has_permissions(request):
return super(SuperOrManagerPermissionsMixin, self).dispatch(
request, *args, **kwargs)
raise Http404 #or return self.handle_no_permission
def user_has_permissions(self, request):
return self.request.user.is_superuser or self.request.user.is_manager
# a bit simplyfied, but with the same redirect for anonymous and logged users
# without permissions
class SuperOrManagerPermissionsMixin(AccessMixin):
def dispatch(self, request, *args, **kwargs):
if self.user_has_permissions(request):
return super(SuperOrManagerPermissionsMixin, self).dispatch(
request, *args, **kwargs)
else:
return self.handle_no_permission(request)
def user_has_permissions(self, request):
return request.user.is_authenticated() and (self.request.user.is_superuser
or self.request.user.is_manager)
class GenerateReportView(SuperOrManagerPermissionsMixin, FormView):
#Remove next two lines, don't need it
def dispatch(self, *args, **kwargs):
#or put some logic here
return super(GenerateReportView, self).dispatch(*args, **kwargs)
また、GenerateReportView(SuperOrManagerPermissionsMixin、FormView)クラスの実装では、ディスパッチメソッドをオーバーライドする必要はありません。
複数の継承を使用していて、親クラスの1つに多少の改善が必要な場合は、最初に改善することをお勧めします。コードをよりクリーンに保ちます。
これは古い投稿ですが、他の人が出くわす可能性があるので、ここに私の提案する解決策を示します。
あなたが言う時
「[...]このビューにいくつかの権限を追加したいたとえば、いくつかの初期変数を設定する、たとえば[...]」
ビューのディスパッチメソッドでこれらの初期変数を設定する代わりに、それらの変数を設定するための個別のメソッドを記述し、そのメソッドをget(および必要に応じてpost)メソッドで呼び出すことができます。これらはディスパッチ後に呼び出されるため、初期変数の設定はミックスインでのディスパッチと競合しません。したがって、メソッドをオーバーライドします
def set_initial_variables():
self.hey = something
return
def get(blablabla):
self.set_initial_variables()
return super(blabla, self).get(blabla)
これはおそらく、ビューのディスパッチでミックスインのコードをコピーして貼り付けるよりもクリーンです。
あなたが挙げた例では、私は Django-braces のUserPassesTestMixin
を使用します。
class GenerateReportView(UserPassesTestMixin, FormView):
def test_func(self, user):
return user.is_superuser or user.is_manager
それがより複雑なロジックに適さない場合、複雑なロジックをうまくカプセル化するため、別のミックスインを作成するとOKアプローチのように聞こえます。
[〜#〜]編集[〜#〜]
Django 1.9以降、UserPassesTestMixinがDjangoに含まれるようになりました。 https://docs.djangoproject.com/en/1.11/topics/auth/default /#Django.contrib.auth.mixins.UserPassesTestMixin
Django serPassesTestMixin mixinまたは @ user_passes_test デコレータで実行できます。
UserPassesTestMixinの例
from Django.contrib.auth.mixins import UserPassesTestMixin
class SuperUserOrManagerRequiredMixin(UserPassesTestMixin):
def test_func(self):
if self.request.user.is_superuser or self.request.user.is_manager:
return True
return False
class MyView(LoginRequiredMixin, SuperUserOrManagerRequiredMixin, View):
...