[django] 콘텐츠 유형이나 모델을 정의하지 않고 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. 

        default_permissions = () # disable "add", "change", "delete"
                                 # and "view" default permissions

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

마우스 오른쪽 후 manage.py makemigrationsmanage.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_rights %}
    <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)


답변

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 클래스는 변경되지 않았지만 완전성을 위해 포함되었습니다.


답변

이것은 대체 솔루션입니다. 먼저 스스로에게 물어보십시오. 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'),
        ]

위의 솔루션은 Permissions.can_search_blue_flower리터럴 문자열 “my_app.can_search_blue_flower”를 사용하는 대신 소스 코드에서 변수 를 사용할 수 있다는 이점이 있습니다 . 이것은 IDE에서 오타가 적고 자동 완성이 더 많다는 것을 의미합니다.


답변

proxy model이를 위해 더미 콘텐츠 유형과 함께 사용할 수 있습니다 .

from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType


class CustomPermission(Permission):

    class Meta:
        proxy = True

    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(CustomPermission, self).save(*args)

이제 모델 의 권한 name과 권한 만 사용하여 권한을 만들 수 있습니다 .codenameCustomPermission

 CustomPermission.objects.create(name='Can do something', codename='can_do_something')

그리고 이와 같이 템플릿에서 사용자 지정 권한 만 쿼리하고 표시 할 수 있습니다.

 CustomPermission.objects.filter(content_type__model='custom permission')


답변