1

试图使我的应用程序可重用并与自定义用户模型兼容,我遇到了以下问题:

假设用户模型如下:

class Member(AbstractUser):
    pass   # basically the builtin User with another name

由于此代码来自django.contrib.auth.models

class PermissionsMixin(models.Model):
    """
    A mixin class that adds the fields and methods necessary to support
    Django's Group and Permission model using the ModelBackend.
    """
    is_superuser = models.BooleanField(_('superuser status'), default=False,
        help_text=_('Designates that this user has all permissions without '
                    'explicitly assigning them.'))
    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.'))
    user_permissions = models.ManyToManyField(Permission,
        verbose_name=_('user permissions'), blank=True,
        help_text='Specific permissions for this user.')

class AbstractUser(AbstractBaseUser, PermissionsMixin):  # <- included there
    ....

(请注意,多对多groups没有定义 a related_name。)

现在,在与小组合作时,我不能这样做:

group.user_set.add(...)

因为反向RelatedManager名称实际上是member_set.

请注意,Member在这种情况下模型的名称是,但它可以是任何其他名称。

现在,我正在执行以下操作:

getattr(group, "%s_set" % settings.AUTH_USER_MODEL.split('.')[-1].lower())

是的,很丑。

问题:对此有任何常见或固定的解决方案吗?

编辑我的最终实现:

@classmethod
def _get_user_reverse_field_name(cls):
    User = get_user_model()
    cls._user_reverse_field_name = User._meta.get_field('groups').related.get_accessor_name()

@property
def members(self):
    if not hasattr(self, '_user_reverse_field_name'):
        self._get_user_reverse_field_name()
    return getattr(self, self._user_reverse_field_name)
4

2 回答 2

3

这应该是您正在寻找的:

In [1]: opts = Group._meta

In [2]: from django.contrib.auth import get_user_model()

In [3]: rel = [r for r in opts.get_all_related_many_to_many_objects() 
               if r.model == get_user_model()]

In [4]: rel
Out[4]: [<RelatedObject: users:user related to groups>]

In [5]: user_rel = rel[0]

In [6]: user_rel.get_accessor_name()
Out[6]: 'user_set'
于 2013-05-26T12:30:28.210 回答
2

您可以inspect在加载所有应用程序和模型之前使用它们进行循环。如果模型related_nameAbstractUser.

话虽如此,那将是非常讨厌的。我有没有提到当你有两个模型派生时它会失败,AbstractUser因为相关名称会发生​​冲突?

您目前实现这一目标的方法非常简单,而且我会保留它。

好吧,我可能更.format()喜欢%

要深入了解反向关系的工作原理,请查看 related.py中的描述符

于 2013-05-23T14:40:33.157 回答