【问题标题】:Chicken and Egg nightmare with Django mixinDjango mixin 的鸡和蛋噩梦
【发布时间】:2020-03-01 22:31:03
【问题描述】:

我正在将一个基于 Django 的大型应用程序从 Django 1.7 应用程序升级到 Django 2.2,并且在使用权限相关的 mixin 时遇到了很多麻烦。

   class PrincipalRoleRelation(models.Model):

    """A role given to a principal (user or group). If a content object is
    given this is a local role, i.e. the principal has this role only for this
    content object. Otherwise it is a global role, i.e. the principal has
    this role generally.

    user
        A user instance. Either a user xor a group needs to be given.

    group
        A group instance. Either a user xor a group needs to be given.

    role
        The role which is given to the principal for content.

    content
        The content object which gets the local role (optional).
    """

       :::

    user         = models.ForeignKey(User,        verbose_name=_(u"User"),         blank=True, null=True, on_delete=models.SET_NULL)
    group        = models.ForeignKey(Group,       verbose_name=_(u"Group"),        blank=True, null=True, on_delete=models.SET_NULL)
    role         = models.ForeignKey(Role,        verbose_name=_(u"Role"),                                on_delete=models.CASCADE)

       :::

但是,这在应用初始化期间无法加载,因为用户、组和角色等也是正在加载的应用,并且“populate() 不可重入”(所以 Dango 抱怨)

我试图通过修改上面的代码来解决这个问题,以创建一种不尝试引用任何其他应用程序的“骨架”类,例如:

app_models_loaded = True

try:
    from django.contrib.auth import get_user_model
    User = get_user_model()
except:
    app_models_loaded = False

if app_models_loaded:

    from django.contrib.auth.models import Group

    user         = models.ForeignKey(User,        verbose_name=_(u"User"),         blank=True, null=True, on_delete=models.SET_NULL)
    group        = models.ForeignKey(Group,       verbose_name=_(u"Group"),        blank=True, null=True, on_delete=models.SET_NULL)
    role         = models.ForeignKey(Role,        verbose_name=_(u"Role"),                                on_delete=models.CASCADE)
              :::

然后在 manage.py 中定义完整的 mixin 类,称为 PrincipalRoleRelation2 并通过代码覆盖骨架类:

from django.contrib import admin

from permissions.models import PrincipalRoleRelation

if admin.site.is_registered(PrincipalRoleRelation):
    admin.site.unregister(PrincipalRoleRelation)

admin.site.register(PrincipalRoleRelation, PrincipalRoleRelation2)

然而,尽管这似乎可行,但我没有看到一些 PrincipalRoleRelation2 属性,例如“角色”,我希望在重新映射的 PrincipalRoleRelation 类中包含所有属性。

我觉得我正在把自己挖到一个更深的洞里,而上述方法是不健全的,永远不会正常工作。因此,我们将不胜感激任何帮助!

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

edit:针对schillingt的评论,User类定义如下:

class User(AbstractBaseUser):  # , PermissionsMixin):
    """ Custom user model
        Currently just used by the tests for django-permissions

        All unique user fields required for a user
        NB: Fields that are customizable across multiple identities will be part of a Profile object
    """
    # Dont use PermissionsMixin since not using contrib.auth.models.Permissions
    # and not using authentication backend perms ... so its only relevant for groups
    # ... however it causes user.groups relations name clashes ..
    # But we are using the groups part with django-permissions:
    groups = models.ManyToManyField(Group, verbose_name=_('groups'),
                                    blank=True, help_text=_('The groups this user belongs to. A user will '
                                                            'get all permissions granted to each of '
                                                            'his/her group.'),
                                    related_name="user_set", related_query_name="user")
    is_superuser = models.BooleanField(_('superuser status'), default=False,
                                       help_text=_('Designates that this user has all permissions without '
                                                   'explicitly assigning them.'))

    username = models.EmailField(_('Email (Username)'), max_length=255, unique=True)
    # Make username an email and just dummy in email here so its clearer for user.email use cases

【问题讨论】:

  • 这似乎是一个循环引用问题,需要知道哪些应用依赖于哪些其他应用。你能告诉我们那个循环引用在哪里吗?
  • 嗨,schillingt,我在问题文本中包含了“用户”类(包括神秘的 cmets)的定义,其他类来自权限/models.py 中的pypi.org/project/django-permissions。这在 Django 1.7 中确实有效 请注意,django-permissions 是一个非常古老的包,但几年都没有更新。
  • 哎呀。那很可能是痛苦的。您可能希望从 fork 该项目开始并使用 Django 3.0 更新它,然后再回到您自己的项目。
  • 我确实 fork 了它,但我不是 Django 专家,也不知道从哪里开始进行任何必要的更新。我宁愿希望它仍然可以工作,或者至少仅以我可以轻松定位和修复的明显方式失败。正如我所说,我的方案几乎似乎奏效了。只是我的替换 mixin 模块似乎没有替换“骨架”版本。也许有替代使用 admin.site.register() ?
  • 很遗憾,我没有这方面的经验,无法快速为您提供帮助。也许其他人会/可以。我必须深入研究项目。

标签: python django mixins


【解决方案1】:

作为循环引用的解决方案,django 可以通过字符串引用指定 ForeignKey(或任何其他关系字段)到相关模型,而不是导入实际的类。

user = models.ForeignKey('users.User', on_delete=models.CASCADE)

这是 imo 推荐的定义相关字段的方法。

【讨论】:

    猜你喜欢
    • 2012-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-21
    • 2020-03-14
    • 2010-11-13
    相关资源
    最近更新 更多