クラスベースビュー Django:ミックスインとディスパッチメソッドを含むクラスベースのビュー




get_context_data (3)

通常、クラスベースのビューの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

期待どおりに動作します。匿名ユーザーがページを訪問すると、 LoginRequiredMixindispatchメソッドがLoginRequiredMixinれ、ユーザーがログインページにリダイレクトされます。

しかし、このビューにいくつかのパーミッションを追加したり、初期変数を設定したりする場合は、

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からの検証を繰り返す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)

この例は単純ですが、ミックスインにはさらに複雑なロジックがいくつかあります。パーミッションをチェックし、計算をしてクラス属性に格納します。

今のところ私はmixinからいくつかのコードをコピーすることで解決します(上記の例のように)。あるいは、ビューのdispatchメソッドから別のミックスインにコードをコピーして、最初のものを継承してから順番に実行します。この新しいミックスインは1つのビューでのみ使用されるため)。

これらの問題を解決するための適切な方法はありますか?


これは古い投稿ですが、他の人が出てくるかもしれないので、私の提案する解決法がここにあります。

あなたが言う時

"[...]このビューの権限を追加したり、初期変数を設定したいとします。

ビューのディスパッチメソッドでこれらの初期変数を設定する代わりに、これらの変数を設定するための分離されたメソッドを記述し、get(および必要に応じてpost)メソッドでそのメソッドを呼び出すことができます。 彼らは発送後に呼ばれるので、あなたの初期変数を設定することはあなたのmixinの発送と衝突しません。 だからメソッドをオーバーライドする

def set_initial_variables():
    self.hey = something
    return 

def get(blablabla):
    self.set_initial_variables()
    return super(blabla, self).get(blabla)

これはおそらく、ビューのディスパッチでミックスインのコードをコピーして貼り付けるよりもきれいです。


すべてのアクセス許可をチェックするカスタムクラスを作成します

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つが何らかの改善を必要とする場合は、まずそれを改善することをお勧めします。 コードをよりきれいに保ちます。


あなたが与えた例では、私はdjango-braces UserPassesTestMixinを使用しdjango-braces

class GenerateReportView(UserPassesTestMixin, FormView):
    def test_func(self, user):
        return user.is_superuser or user.is_manager

それがあなたのより複雑なロジックには適していない場合、複雑なロジックをうまくカプセル化するので、別のミックスインを作成することはOKアプローチのように聞こえます。

EDIT
django 1.9以降、UserPassesTestMixinはdjangoに含まれていhttps://docs.djangoproject.com/en/1.11/topics/auth/default/#django.contrib.auth.mixins.UserPassesTestMixinhttps://docs.djangoproject.com/en/1.11/topics/auth/default/#django.contrib.auth.mixins.UserPassesTestMixin : https://docs.djangoproject.com/en/1.11/topics/auth/default/#django.contrib.auth.mixins.UserPassesTestMixin





mixins