Programing

콘텐츠 유형이나 모델을 정의하지 않고 Django 권한을 어떻게 사용할 수 있습니까?

lottogame 2020. 10. 23. 07:29
반응형

콘텐츠 유형이나 모델을 정의하지 않고 Django 권한을 어떻게 사용할 수 있습니까?


권한 기반 시스템을 사용하여 Django 애플리케이션 내에서 특정 작업을 제한하고 싶습니다. 이러한 작업은 특정 모델 (예 : 응용 프로그램의 섹션 액세스, 검색 ...)과 관련 될 필요가 없습니다. 따라서 모델에 설치된 콘텐츠 유형에 대한 참조가 필요 하기 때문에 스톡 권한 프레임 워크를 직접 사용할 수 없습니다 Permission.

내 자신의 권한 모델을 작성할 수 있지만 다음과 같이 Django 권한에 포함 된 모든 기능을 다시 작성해야합니다.

django-authoritydjango-guardian같은 일부 앱을 확인 했지만 객체 별 권한을 허용하여 모델 시스템과 더욱 결합 된 권한을 제공하는 것 같습니다.

프로젝트에 대한 모델 ( User제외 Group)을 정의하지 않고이 프레임 워크를 재사용 할 수있는 방법이 있습니까?


Django의 Permission모델 에는 ContentType인스턴스 가 필요 합니다 .

한 가지 방법은 ContentType모델과 관련이없는 더미 만드는 것입니다 ( app_labelmodel필드는 모든 문자열 값으로 설정할 수 있음).

모든 것을 깔끔하고 멋지게 만들고 싶다면 더미의 모든 추악한 세부 사항을 처리하고 "모델없는"권한 인스턴스를 만드는 Permission 프록시 모델만들 수 있습니다 ContentType. Permission실제 모델과 관련된 모든 인스턴스 를 필터링하는 사용자 지정 관리자를 추가 할 수도 있습니다 .


아직 찾고 계신 분들을 위해 :

데이터베이스 테이블없이 보조 모델을 생성 할 수 있습니다. 이 모델은 필요한 모든 권한을 프로젝트에 가져올 수 있습니다. 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 %}

다음 곤잘로의 조언을 , 내가 사용하는 프록시 모델사용자 정의 관리자를 더미 콘텐츠 형식으로 내 "modelless"권한을 처리 할 수 있습니다.

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)

Fix for Chewie's answer in Django 1.8, which as been requested in a few comments.

It says in the release notes:

The name field of django.contrib.contenttypes.models.ContentType has been removed by a migration and replaced by a property. That means it’s not possible to query or filter a ContentType by this field any longer.

So it's the 'name' in reference in ContentType that the uses not in GlobalPermissions.

When I fix it I get the following:

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)

The GlobalPermissionManager class is unchanged but included for completeness.


Instead of writing and running this code which inserts records into the database you could just insert the records into your database (obviously editing the primary and foreign keys as needed)

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');

And then in your application admin you would have the ability to assign 'Is Staff Member' to your users or groups. To check this permission in your class you would write

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)

This is alternative solution. First ask yourself: Why not create a Dummy-Model which really exists in DB but never ever gets used, except for holding permissions? That's not nice, but I think it is valid and straight forward solution.

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'),
        ]

Above solution has the benefit, that you can use the variable Permissions.can_search_blue_flower in your source code instead of using the literal string "my_app.can_search_blue_flower". This means less typos and more autocomplete in IDE.

참고URL : https://stackoverflow.com/questions/13932774/how-can-i-use-django-permissions-without-defining-a-content-type-or-model

반응형