【问题标题】:Creating custom permission in data migration在数据迁移中创建自定义权限
【发布时间】:2015-10-13 10:41:13
【问题描述】:

我试图在迁移中创建自定义权限,但是运行迁移后,权限表中没有创建权限。有人能指出错误是什么吗? 此外,我不确定应该使用什么作为 ContentType 的相关模型,因为该权限用于限制可以查看显示网站上用户摘要的页面的用户。 任何帮助将不胜感激,谢谢。

def add_view_aggregated_data_permissions(apps, schema_editor):
    ContentType = apps.get_model('django', 'ContentType')
    Permission = apps.get_model('auth', 'Permission')
    content_type = ContentType.objects.get(app_label='auth', model='user')
    permission = Permission.objects.create(codename='can_view_data',
                                           name='Can view data',
                                           content_type=content_type)

【问题讨论】:

  • 为什么要以这种方式创建权限?
  • 这是错误的做法吗?我想为视图创建权限,我应该怎么做?

标签: django django-migrations django-permissions


【解决方案1】:

我建议您使用Django documentation 中描述的标准方式来使用自定义权限。您将完全避免许多问题。

要为给定模型对象创建自定义权限,请使用权限模型元属性。

此示例模型创建自定义权限:

class MyModel(models.Model):
    ...
    class Meta:
        permissions = (
            ('view_data', "Can see available data"),
        )

这样做的唯一一件事就是在您运行manage.py migrate 时创建那些额外的权限。当用户尝试访问应用程序提供的功能时,您的代码负责检查这些权限的值...

然后你可以使用 permission_required 装饰器和你的视图来检查特定的权限:

from django.contrib.auth.decorators import permission_required

@permission_required('myapp.view_data')
def my_view(request):
    ...

【讨论】:

  • 这是否意味着权限将与用户模型相关联?我感到困惑的部分是我的权限仅用于限制对视图的访问,因此我不确定将其与哪个模型相关联。另外,我可以将此权限添加到管理站点中的用户吗?编辑:刚刚意识到我不能在用户模型上编辑代码,那么我应该把元代码放在哪里?我是新手,所以我可能有很多问题......
  • 权限将与用户模型相关联是什么意思?所有权限本质上都与用户模型相关联。如果您特别需要添加权限,例如查看用户,那么这完全是另一回事,您需要扩展或覆盖 User 模型。我想您的视图显示至少来自某个模型的数据,因此您可以向该模型添加权限。
  • 啊,好吧,我认为该关联类似于将权限与哪个模型能够获得该权限相关联,但这并没有真正的意义,我想这就是我感到困惑的原因。感谢您的澄清 :) 那么如果视图包含来自不同模型的数据,我只需将权限添加到一个模型?
  • 欢迎。这取决于整个应用程序,您只能将权限添加到单个模型,或添加到所有模型并检查所有权限(更安全)。
  • 注意:该权限仅在 migrate 命令的末尾可用,因此如果您有(即)引用新权限的后续 RunPython 迁移,他们将看不到新权限,如果在同一 migrate 命令中应用。在这种情况下,您必须分两个阶段应用它们。
【解决方案2】:

我想为所有应用模型创建自定义权限(读取)。我做了这两个步骤:

  1. 从 DjangoModelPermissions 创建扩展权限:

    class DjangoModelPermissionsExtended(DjangoModelPermissions):
        """
        """
        perms_map = {
            'GET': ['%(app_label)s.read_%(model_name)s'],
            'OPTIONS': [],
            'HEAD': [],
            'POST': ['%(app_label)s.add_%(model_name)s'],
            'PUT': ['%(app_label)s.change_%(model_name)s'],
            'PATCH': ['%(app_label)s.change_%(model_name)s'],
            'DELETE': ['%(app_label)s.delete_%(model_name)s'],
        }
    
  2. 把它放在每个视图我想有读取权限:

    class ExampleViewSet(viewsets.ModelViewSet):
        permission_classes = (
            DjangoModelPermissionsExtended,
        )
    
  3. 创建一个django commandcustomread.py:

    from django.core.management.base import BaseCommand, CommandError
    from project.app import models as app_models
    from django.db import models
    from django.contrib.auth.models import Permission
    from django.contrib.contenttypes.models import ContentType
    import inspect
    
    class Command(BaseCommand):
    help = 'Create the read permission to app models'
    
    def handle(self, *args, **options):
        for name, obj in inspect.getmembers(app_models):
            if inspect.isclass(obj) and issubclass(obj, models.Model):
                try:
                    self.add_canread(obj)
                    self.stdout.write(self.style.SUCCESS(
                        'created permission for %s' % obj
                    ))
                except Exception as e:
                    self.stdout.write(self.style.ERROR(
                        'Permission already exists for %s' % obj
                    ))
    
    def add_canread(self, object_class):
        """This a function that can be executed in order to create
        new permissions (read view) to a class in DB.
    
        """
        if inspect.isclass(object_class):
            content_type = ContentType.objects.get_for_model(object_class)
            permission = Permission.objects.create(
                codename='read_{}'.format(object_class._meta.model_name),
                name='Can view {}'.format(object_class.__name__),
                content_type=content_type,
            )
        else:
            msg = "The object is not a class"
            print(msg)
    
  4. 迁移后执行:

    python manage.py customread
    

【讨论】:

    【解决方案3】:

    从 django 1.8 和内置迁移开始,这非常轻松。

    1. 您需要做的就是将您想要的权限添加到相关的 型号
    2. 运行 makemigration

      ./manage.py makemigrations

    3. 运行在上述步骤中创建的迁移

      ./manage.py 迁移

    【讨论】:

      猜你喜欢
      • 2021-06-29
      • 2015-05-31
      • 2019-10-09
      • 2017-05-27
      • 2021-12-31
      • 1970-01-01
      • 2020-04-10
      • 2018-09-10
      • 1970-01-01
      相关资源
      最近更新 更多