尝试使我的应用程序可重用并与自定义用户模型兼容,我遇到了以下问题:
假设用户模型如下:
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)
答案 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
中的描述符