如何在不定义内容类型或模型的情况下使用Django权限?

Che*_*wie 75 django django-permissions

我想使用基于权限的系统来限制我的Django应用程序中的某些操作.这些操作不需要与特定模型相关(例如,访问应用程序中的部分,搜索......),因此我无法直接使用库存权限框架,因为Permission模型需要引用已安装的内容类型.

我可以编写自己的权限模型,但后来我必须重写Django权限中包含的所有好东西,例如:

我已经检查了一些像django-authoritydjango-guardian这样的应用程序,但它们似乎通过允许每个对象的权限提供更多耦合到模型系统的权限.

有没有办法重新使用这个框架,而不必定义任何模型(除了UserGroup)的项目?

Dmi*_*try 102

对于那些仍在搜索的人:

您可以创建没有数据库表的辅助模型.该模型可以为您的项目带来您需要的任何许可.无需处理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'), 
        )
Run Code Online (Sandbox Code Playgroud)

之后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 %}
Run Code Online (Sandbox Code Playgroud)

  • 我建议在 Meta 类中添加以下内容:“default_permissions = ()”。这将阻止 Django 自动为此模型创建默认的添加/更改/删除/查看权限,如果您使用此方法,这很可能是不必要的。 (6认同)
  • 您是否将您的应用添加到您的项目 (INSTALLED_APPS) 中? (3认同)
  • 那是天才,拯救我的一天! (2认同)
  • 我运行manage.py migration之后没有任何变化...我没有看到任何新的权限:( (2认同)
  • 这个答案是完美的。我还[]设置了default_permissions,在模型的save()上引发NotImplementedError,并且如果非托管模型对于此权限而言确实如此,则可以考虑使has _ * _ permission()返回False。 (2认同)
  • 这种方法的一个小问题是 [`dumpdata` 按照设计仍然包含非托管表](https://code.djangoproject.com/ticket/13816),因此没有附加参数的 `./manage.py dumpdata` 将丢失的表失败。 (2认同)

Gon*_*alo 51

Django的Permission模型需要一个ContentType实例.

我认为一种方法是创建一个ContentType与任何模型无关的虚拟(app_labelmodel字段可以设置为任何字符串值).

如果你想要一切都干净又漂亮,你可以创建一个Permission 代理模型来处理虚拟的所有丑陋细节ContentType并创建"无模型"权限实例.您还可以添加自定义管理器,筛选出Permission与实际模型相关的所有实例.

  • 如果您不介意,我将通过实施完成您的答案. (3认同)

Che*_*wie 49

根据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)
Run Code Online (Sandbox Code Playgroud)

  • 感谢代码,还可以展示如何使用此代码的示例. (10认同)
  • 要创建GlobalPermission:从app.models导入GlobalPermission gp = GlobalPermission.objects.create(codename ='can_do_it',name ='Can do it')运行后,您可以像任何其他权限一样将该权限添加到用户/组. (4认同)
  • @JulienGrenier Django 1.8中的代码中断:```FieldError:无法将关键字'name'解析为字段.选择是:app_label,id,logentry,model,permission```. (3认同)
  • 该模型许可应该在哪里生活? (2认同)
  • 警告:较新版本的Django(至少1.10)需要覆盖方法"get_queryset"(注意单词"query"和"set"之间缺少_. (2认同)

rga*_*ans 8

修复了Chewie在Django 1.8中的回答,正如一些评论所要求的那样.

它在发行说明中说:

django.contrib.contenttypes.models.ContentType的名称字段已被迁移删除,并由属性替换.这意味着不再可以通过此字段查询或过滤ContentType.

因此,它是ContentType中引用的"名称",而不是在GlobalPermissions中使用.

当我修复它时,我得到以下内容:

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)
Run Code Online (Sandbox Code Playgroud)

GlobalPermissionManager类未更改,但包含完整性.


gue*_*tli 5

这是替代解决方案。首先问问自己:为什么不创建一个真正存在于数据库中但从未被使用过的虚拟模型,除了持有权限?这不好,但我认为这是有效且直接的解决方案。

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'),
        ]
Run Code Online (Sandbox Code Playgroud)

上述解决方案的好处是,您可以Permissions.can_search_blue_flower在源代码中使用该变量,而不是使用文字字符串“my_app.can_search_blue_flower”。这意味着在 IDE 中更少的拼写错误和更多的自动完成。