Python
Django

DjangoのPermissionモデルを利用してViewを制限する

More than 1 year has passed since last update.

DjangoにはPermissionというモデルがあり、Djangoのmodelを作成すると自動で生成されます。それによって管理画面では対応する権限を持つユーザーのみがテーブルデータを作成・更新・削除できるといった制限が可能です。今回はこのPermissionを使ってViewの制限をしたいと思います。


独自のPermissionを作る

既存のPermissionデータを使わずに新しく作ってみます。


ContentTypeの指定

Permissionモデルは外部キーとしてContentTypeを指定する必要があるので、対応するContentTypeが無くてはなりません。制限しようとしているViewのあるアプリケーションのContentTypeを指定すればいいと思いますが、独自のものを作ってもいいかもしれません。

from django.contrib.contenttypes.models import ContentType

ContentType.objects.create(
app_label='app_label', name='name', model='model')

app_labelとして指定しているのはアプリケーション名。つまりsettingsのINSTALLED_APPSなどに指定するモジュール名の末尾です。


Permissionデータの作成

from django.contrib.auth.models import Permission

from django.contrib.contenttypes.models import ContentType

content_type = ContentType.objects.get(
app_label='app_label', name='name', model='model')

Permission.objects.create(
content_type_id=content_type.id, name='name', codename='codename')

name'Can add permission'などパーミッションの表示名で、codename'add_permission'など、識別名です。


ユーザーにPermissionを付与

Djangoの管理画面のユーザー編集画面から権限の付与ができます。

perm.png


ユーザーが特定のPermissionを持っているか調べる

Userインスタンスのhas_permを呼べば特定のPermissionを持っているか確認できます。引数に渡すのは'app_label.codename'という形になります。たとえばユーザー追加のパーミッションは'auth.add_user'です。

from django.contrib.auth import get_user_model

User = get_user_model()
user = User.objects.get(pk=1)

user.has_perm('{app_label}.{codename}'.format(
app_label='app_label', codename='codename'))


デコレーターでViewを制限

(追記あり)

参考として、Djangoではスタッフユーザーだけが見る事ができるViewを作る場合、デコレータを利用する方法があります。

from django.contrib.admin.views.decorators import staff_member_required

from django.utils.decorators import method_decorator
from django.views.generic.base import View

class SpamView(View):
@method_decorator(staff_member_required)
def dispatch(self, *args, **kwargs):
return super(SpamView, self).dispatch(*args, **kwargs)

これをまねて特定のパーミッションを持つユーザーだけが見る事ができるViewを作ります。


decorators.py

from django.contrib.auth import REDIRECT_FIELD_NAME

from django.contrib.auth.decorators import user_passes_test

def get_permission_deco(permission_codename,
redirect_field_name=REDIRECT_FIELD_NAME,
login_url='admin:login'):
def deco(view_func):
return user_passes_test(
lambda u: u.has_perm(permission_codename),
login_url=login_url,
redirect_field_name=redirect_field_name
)(view_func)
return deco



view.py

from django.utils.decorators import method_decorator

from django.views.generic.base import View

from .decorators import get_permission_deco

class EggView(View):
@method_decorator(get_permission_deco('app_label.codename'))
def dispatch(self, *args, **kwargs):
return super(EggView, self).dispatch(*args, **kwargs)



(追記)

小細工しなくてもDjangoにはpermission_requiredというのがありました。

https://docs.djangoproject.com/ja/1.10/topics/auth/default/#the-permission-required-decorator


カスタムタグでテンプレートを制限

カスタムタグの作り方の詳細はこの記事の範囲を超えますので省略しますが、カスタムタグを使ってテンプレートを制限する事もあるかと思うので一例を載せておきます。


perm_extra.py

from django import template

register = template.Library()

@register.filter(name='has_perm')
def has_perm(user, permission_name):
return user.has_perm(permission_name)


{% load perm_extra %}

{% if user|has_perm:'app_label.codename' %}
<a href="/path">編集ページへ</a>
{% else %}
<del>編集ページへ</del>(権限がありません)
{% endif %}