django获得名称不明的相关经理

时间:2013-05-21 11:52:18

标签: django django-models

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

假设用户模型如下:

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未定义related_name。)

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

group.user_set.add(...)

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

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

现在,我正在做以下事情:

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

是的,非常难看。

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

使用我的最终实施进行编辑:

@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)

2 个答案:

答案 0 :(得分: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'

答案 1 :(得分:2)

您可以使用inspect在加载之前循环浏览所有应用和模型。如果模型是related_name的子类,那么在该循环中你可以修补字段的AbstractUser属性。

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

你目前实现这一目标的方式非常简单,只需一个班轮,我会保留它。

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

要深入了解反向关系如何工作,请查看related.py

中的描述符