web-dev-qa-db-ja.com

コンテンツタイプまたはモデルを定義せずにDjango=パーミッションを使用するにはどうすればよいですか?

権限ベースのシステムを使用して、Djangoアプリケーション内の特定のアクションを制限します。これらのアクションは特定のモデルに関連する必要はありません(アプリケーションのセクションへのアクセス、検索など)。 。)、 ストックパーミッションフレームワーク を直接使用することはできません。これは、 Permission モデルがインストールされたコンテンツタイプへの参照を必要とするためです。

独自のアクセス許可モデルを作成することもできますが、次に、Djangoアクセス許可に含まれるすべての特典を書き換える必要があります。

Django-authorityDjango-guardian などのアプリをいくつかチェックしましたが、オブジェクトごとのアクセス許可を許可することで、モデルシステムにさらに結合したアクセス許可を提供するようです。

プロジェクトのモデル(UserおよびGroup以外)を定義せずにこのフレームワークを再利用する方法はありますか?

72
Chewie

DjangoのPermissionモデル ContentTypeインスタンスが必要

それを回避する1つの方法は、どのモデルにも関係しないダミーのContentTypeを作成することだと思います(app_labelおよびmodelフィールドは、任意の文字列値に設定できます)。

すべてをきれいにしたい場合は、Permissionproxy model を作成して、ダミーのContentTypeのい詳細をすべて処理し、「モデルレス」権限インスタンスを作成できます。 。また、実際のモデルに関連するすべてのPermissionインスタンスを除外するカスタムマネージャーを追加することもできます。

47
Gonzalo

まだ検索しているあなたのために:

データベーステーブルなしで補助モデルを作成できます。そのモデルは、必要な許可をプロジェクトにもたらすことができます。 ContentTypeを処理したり、Permissionオブジェクトを明示的に作成したりする必要はありません。

from Django.db import models

class RightsSupport(models.Model):

    class Meta:

        managed = False  # No database table creation or deletion  \
                         # operations will be performed for this model. 

        permissions = ( 
            ('customer_rights', 'Global customer rights'),  
            ('vendor_rights', 'Global vendor rights'), 
            ('any_rights', 'Global any rights'), 
        )

直後の manage.py migrateこれらの権限は他の権限と同様に使用できます。

# Decorator

@permission_required('app.customer_rights')
def my_search_view(request):
    …

# Inside a view

def my_search_view(request):
    request.user.has_perm('app.customer_rights')

# In a template
# The currently logged-in user’s permissions are stored in the template variable {{ perms }}

{% if perms.app.customer_rigths %}  
    <p>You can do any customer stuff</p>
{% endif %}
97
Dmitry

Gonzaloのアドバイス に続いて、ダミーコンテンツタイプで「モデルレス」権限を処理するために プロキシモデルカスタムマネージャー を使用しました。

from Django.db import models
from Django.contrib.auth.models import Permission
from Django.contrib.contenttypes.models import ContentType


class GlobalPermissionManager(models.Manager):
    def get_query_set(self):
        return super(GlobalPermissionManager, self).\
            get_query_set().filter(content_type__name='global_permission')


class GlobalPermission(Permission):
    """A global permission, not attached to a model"""

    objects = GlobalPermissionManager()

    class Meta:
        proxy = True

    def save(self, *args, **kwargs):
        ct, created = ContentType.objects.get_or_create(
            name="global_permission", app_label=self._meta.app_label
        )
        self.content_type = ct
        super(GlobalPermission, self).save(*args, **kwargs)
48
Chewie

Django 1.8のChewieの答えを修正しました。これはいくつかのコメントで要求されました。

リリースノートには次のように書かれています:

Django.contrib.contenttypes.models.ContentTypeの名前フィールドは、移行によって削除され、プロパティに置き換えられました。つまり、このフィールドでContentTypeをクエリまたはフィルタリングすることはできなくなります。

したがって、GlobalPermissionsではなく使用するのは、ContentTypeの参照の「名前」です。

修正すると、次のようになります。

from Django.db import models
from Django.contrib.auth.models import Permission
from Django.contrib.contenttypes.models import ContentType


class GlobalPermissionManager(models.Manager):
    def get_queryset(self):
        return super(GlobalPermissionManager, self).\
            get_queryset().filter(content_type__model='global_permission')


class GlobalPermission(Permission):
    """A global permission, not attached to a model"""

    objects = GlobalPermissionManager()

    class Meta:
        proxy = True
        verbose_name = "global_permission"

    def save(self, *args, **kwargs):
        ct, created = ContentType.objects.get_or_create(
            model=self._meta.verbose_name, app_label=self._meta.app_label,
        )
        self.content_type = ct
        super(GlobalPermission, self).save(*args)

GlobalPermissionManagerクラスは変更されていませんが、完全を期すために含まれています。

8
rgammans

これは代替ソリューションです。最初に自問してください:DBには実際に存在するが、使用されることのないダミーモデルを作成して、許可を保持することを除きます。それはニースではありませんが、それは有効で簡単な解決策だと思います。

from Django.db import models

class Permissions(models.Model):

    can_search_blue_flower = 'my_app.can_search_blue_flower'

    class Meta:
        permissions = [
            ('can_search_blue_flower', 'Allowed to search for the blue flower'),
        ]

上記のソリューションには、リテラル文字列「my_app.can_search_blue_flower」を使用する代わりに、ソースコードで変数Permissions.can_search_blue_flowerを使用できるという利点があります。これは、IDEのタイプミスを減らし、オートコンプリートを増やすことを意味します。

1
guettli

データベースにレコードを挿入するこのコードを記述して実行する代わりに、データベースにレコードを挿入するだけで済みます(明らかに必要に応じて主キーと外部キーを編集します)。

insert into Django_content_type(id,name,app_label,model) values (22,'app_permission','myapp','app_permission');
insert into auth_permission(id,name,content_type_id,codename) values (64,'Is Staff Member',22,'staff_member');

そして、アプリケーション管理者では、「スタッフメンバー」をユーザーまたはグループに割り当てることができます。クラスでこの許可を確認するには、次のように記述します。

from Django.contrib.auth.decorators import permission_required
from Django.utils.decorators import method_decorator
from Django.views.generic import TemplateView

class MyClass(TemplateView):
    template_name = myapp/index.html'

    @method_decorator(permission_required(['myapp.staff_member'],raise_exception=True))
    def dispatch(self, *args, **kwargs):
        return super(MyClass, self).dispatch(*args, **kwargs)
1
Lehrian