Django: モデルインスタンスごとに異なるアクセス許可を設定したい? `db.models.Options.default_permissions` を超えた高度なテクニック


django.db.models.Options.default_permissions は、Django モデルクラスに対してデフォルトのアクセス許可を設定するためのオプションです。これは、特定のユーザーグループがモデルインスタンスに対して実行できる操作を制御するために使用されます。

設定方法

default_permissions オプションは、モデルクラスのメタオプションとして設定されます。以下の例のように、タプル形式で設定します。

class MyModel(models.Model):
    # ... その他のモデルフィールド

    class Meta:
        default_permissions = (
            'add',
            'change',
            'delete',
            'view',
        )

上記の例では、MyModel インスタンスに対して以下の操作が許可されます。

  • インスタンスを表示する (view)
  • インスタンスを削除する (delete)
  • 既存のインスタンスを編集する (change)
  • 新しいインスタンスを作成する (add)

許可名の詳細

default_permissions オプションで使用できる許可名は以下の通りです。

  • use: インスタンスを使用する
  • lookup: インスタンスを検索する
  • view: インスタンスを表示する
  • delete: インスタンスを削除する
  • change: 既存のインスタンスを編集する
  • add: 新しいインスタンスを作成する

カスタム許可

default_permissions オプションに加えて、カスタム許可を作成することもできます。これにより、よりきめ細かなアクセス制御が可能になります。カスタム許可を作成するには、django.contrib.admin.ModelAdmin クラスの has_model_perm メソッドをオーバーライドします。

例:MyModel インスタンスに対して publish 操作を許可する

from django.contrib import admin

class MyModelAdmin(admin.ModelAdmin):
    def has_model_perm(self, request, model_admin):
        # 現在のユーザーが 'publish' 許可を持っているかどうかを確認する
        if request.user.has_perm('my_app.publish'):
            return True
        return super().has_model_perm(request, model_admin)

上記の例では、my_app.publish 許可を持つユーザーのみが MyModel インスタンスを公開できるようになります。

  • default_permissions オプションは、オブジェクトレベルのアクセス制御を提供しません。オブジェクトレベルのアクセス制御には、django.contrib.auth.models.User モデルとの関係を使用する必要があります。
  • default_permissions オプションは、モデルのスーパーユーザーに対してのみ適用されます。スーパーユーザーは、モデルインスタンスに対して常にすべての操作を実行できます。


モデルクラスとデフォルトのアクセス許可

from django.db import models

class MyModel(models.Model):
    name = models.CharField(max_length=255)

    class Meta:
        default_permissions = (
            'add',
            'change',
            'delete',
            'view',
        )
  • インスタンスを表示する (view)
  • インスタンスを削除する (delete)
  • 既存のインスタンスを編集する (change)
  • 新しいインスタンスを作成する (add)

カスタム許可

from django.contrib import admin

class MyModelAdmin(admin.ModelAdmin):
    def has_model_perm(self, request, model_admin):
        # 現在のユーザーが 'publish' 許可を持っているかどうかを確認する
        if request.user.has_perm('my_app.publish'):
            return True
        return super().has_model_perm(request, model_admin)
from django.db import models
from django.contrib.auth import models as auth_models

class MyModel(models.Model):
    name = models.CharField(max_length=255)
    owner = models.ForeignKey(auth_models.User, on_delete=models.CASCADE)

    class Meta:
        default_permissions = (
            'add',
            'change',
            'delete',
            'view',
        )

この例では、MyModel インスタンスの所有者のみがそのインスタンスに対してすべての操作を実行できます。他のユーザーは、スーパーユーザーである場合を除き、そのインスタンスに対して view 操作のみを実行できます。

  • Django のアクセス許可システムは非常に強力で、さまざまなユースケースに対応できます。詳細については、Django のドキュメントを参照してください。
  • 上記のコードはあくまで例であり、実際の用途に合わせて変更する必要があります。


カスタムビューセットを使用する

カスタムビューセットを使用して、モデルインスタンスに対して実行できる操作を制御することができます。これは、よりきめ細かなアクセス制御が必要な場合に役立ちます。

例:MyModel インスタンスに対して publish 操作を許可するビューセット

from django.views.generic import View
from django.contrib.auth.mixins import PermissionRequiredMixin

class PublishMyModelView(PermissionRequiredMixin, View):
    permission_required = 'my_app.publish'

    def post(self, request, pk):
        # 'publish' 許可を持つユーザーのみがインスタンスを公開できる
        if self.has_permission():
            my_model_instance = MyModel.objects.get(pk=pk)
            my_model_instance.publish()
            return HttpResponseRedirect(reverse('my_app:my_model_list'))
        else:
            return HttpResponseForbidden()

カスタム管理者クラスを使用する

カスタム管理者クラスを使用して、モデルインスタンスに対して表示される操作を制御することができます。これは、管理画面でのアクセス制御を簡素化したい場合に役立ちます。

例:MyModel インスタンスに対して publish 操作のみを表示するカスタム管理者クラス

from django.contrib import admin

class MyModelAdmin(admin.ModelAdmin):
    def get_actions(self, request):
        actions = super().get_actions(request)
        if not request.user.has_perm('my_app.publish'):
            del actions['publish']
        return actions

ロールベースのアクセス制御を使用する

ロールベースのアクセス制御システムを使用して、ユーザーに割り当てられたロールに基づいてアクセス許可を制御することができます。これは、複雑なアクセス制御要件がある場合に役立ちます。

例:django-rolepermissions パッケージを使用する

# settings.py

INSTALLED_APPS = [
    # ... その他のアプリ
    'django_rolepermissions',
]

ROLEPERMISSIONS_MODULE = 'my_app.roles'
# my_app/roles.py

from django_rolepermissions.roles import roles

class MyModelEditor(roles.BaseRole):
    can_edit = True

roles.register(MyModelEditor)

上記の例では、MyModelEditor ロールを持つユーザーのみが MyModel インスタンスを編集できるようになります。

アクセス許可のミドルウェアを使用する

アクセス許可のミドルウェアを使用して、リクエストごとにアクセス許可をチェックすることができます。これは、リクエストごとにアクセス許可を動的に設定する必要がある場合に役立ちます。

例:django-guardian パッケージを使用する

# settings.py

AUTHENTICATION_BACKENDS = [
    # ... その他の認証バックエンド
    'guardian.backends.ObjectPermissionBackend',
]

MIDDLEWARE = [
    # ... その他のミドルウェア
    'guardian.middleware.PermissionMiddleware',
]
# my_app/models.py

from guardian.shortcuts import assign

def assign_my_model_permissions(user, my_model_instance):
    # ユーザーに 'my_app.publish' 許可を割り当てる
    assign('my_app.publish', user, my_model_instance)

上記の例では、assign_my_model_permissions 関数を使用して、ユーザーに MyModel インスタンスに対する my_app.publish 許可を割り当てています。