【问题标题】:Django: How to call the same model class inside it s self?Django:如何在自身内部调用相同的模型类?
【发布时间】:2021-08-23 17:51:10
【问题描述】:

我有一个函数make_fields_permissions,我需要在模型类中使用它来解析字段并为每个字段设置权限,例如[('can_view_first_name_field','can view first name'),...]

  • 目标我需要调用并覆盖Person 类并在其中自我
  • 我试过了

def __init__(self,*args, **kwargs):
    self.Meta.permissions = make_fields_permissions(self.model)
    super().__init__(*args, **kwargs)

  • 我的代码如下所示
from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

    def __init__(self, *args, **kwargs):
        # kwargs['user']['permissions'] =  make_fields_permissions(Profile)
        # x = self['age']
        super().__init__(*args, **kwargs)


    class Meta:
        permissions = make_fields_permissions(Person) #< I can't use the same model inside meta

【问题讨论】:

  • 您可以将逻辑引入到 create Permission 对象:docs.djangoproject.com/en/3.2/ref/contrib/auth/… 所以不要在Meta 中使用这些,而是​​创建一个检查字段的函数给定模型,并构造Permission 对象。
  • 你的意思是在课外我不得不说Person.permissions = myFunction(Person)
  • 或者你可以决定涉足元类(可以自定义类的创建方式)并尝试从ModelBase继承。虽然这很容易破解,因为ModelBase(这是Model 使用的元类)已经做了很多事情,所以这种修改需要非常小心,它会更容易让您在应用程序配置ready 方法中执行此操作,并尝试通过遍历模型字段来获得权限。
  • @alial-karaawi:不,只是myFunction(Person),然后你就创建权限了。例如,您可以在应用程序配置的 ready 方法中触发此操作,就像 Abdul 说的那样。
  • @AbdulAzizBarkat 你能把它写在答案中吗?我不明白这样吗?

标签: python python-3.x django python-2.7


【解决方案1】:

你的目标如下:

  • Goal X(真正的目标):根据模型字段动态创建权限
  • 目标 Y(将实现 X 的感知目标):在创建模型类时调用它。

注意:见What is the XY problem?

让我们首先讨论目标 Y 以及它为何过于复杂且有些不可行。当一个人想要自定义一个类的创建方式时,可以使用metaclasses,乍一看,这似乎是满足您需求的完美解决方案(事实上,如果您确实创建了一个正确的将是)。但这里的问题是Model 已经 有一个元类ModelBase 并且它已经做了很多事情并且有点复杂。如果我们想要一个自定义元类,我们需要从它继承并非常仔细围绕它的实现来做我们想做的事情。此外,制作它并不是故事的结局,因为那时我们需要维护它,因为它很容易被 Django 更新破坏。因此目标Y是不可行的。

继续执行实际的目标 X 来做到这一点,可以Programmatically create permissions [Django docs]。执行此操作的好地方是在应用程序配置ready 方法中。对于使用startapp 创建的所有应用程序,都有一个apps.py 文件,该文件具有从AppConfig 继承的appconfig,当加载模型时,它的ready 方法被调用。因此,此方法用于执行各种任务,如附加信号、各种设置(如任务)等。修改应用程序的 appconfig 以通过编程方式创建权限,如下所示:

from django.apps import AppConfig


class YourAppConfig(AppConfig):
    default_auto_field = 'django.db.models.AutoField' # Don't modify, keep it as it is in your code
    name = 'your_app' # Don't modify, keep it as it is in your code
    
    def ready(self):
        from django.contrib.auth.models import Permission
        from django.contrib.contenttypes.models import ContentType
        from path.to import make_fields_permissions
        from .models import Person
        # import models here, not outside as models may not be loaded yet
        content_type = ContentType.objects.get_for_model(Person)
        for codename, name in make_fields_permissions(Person):
            Permission.objects.get_or_create(
                codename=codename, # 'can_view_first_name_field'
                name=name, # 'can view first name'
                content_type=content_type,
            )

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 2010-12-09
    • 2011-06-22
    • 2020-07-27
    • 2019-05-26
    • 2016-10-06
    • 2018-01-12
    相关资源
    最近更新 更多