Python 检查Django中M2M关系中的多个值

Python 检查Django中M2M关系中的多个值,python,django,django-models,django-views,django-queryset,Python,Django,Django Models,Django Views,Django Queryset,在英语中,我想检查用户的类型是查看器、版主还是管理员 以下是mymodels.py的相关部分 class UserType( models.Model ) : name = models.CharField( max_length = 135 ) # id | name #----+------------------ # 1 | tenant # 2 | property manager # 3 | property owne

在英语中,我想检查用户的类型是查看器、版主还是管理员

以下是my
models.py的相关部分

class UserType( models.Model ) :
    name = models.CharField( max_length = 135 )

    # id |       name
    #----+------------------
    #  1 | tenant
    #  2 | property manager
    #  3 | property owner
    #  4 | vendor manager
    #  5 | vendor
    #  6 | viewer
    #  7 | moderator
    #  8 | administrator

class UserProfile( models.Model ) :
    user       = models.OneToOneField( User )
    user_types = models.ManyToManyField( UserType, null = True, blank = True )
顺便说一下,我将
user.profile
设置为与
user.get\u profile()
相同

在我的
views.py
code中,我想进行检查。我知道了

[ user_type.pk for user_type in user.profile.user_types.all() ]
将为
用户的
用户类型
提供一个
pk
列表,如
[1,2,6]
。这意味着该特定用户是租户(1)、物业经理(2)和查看者(6)

如果我只想检查一个
用户类型
,那么我只需

if 6 in [ user_type.pk for user_type in user.profile.user_types.all() ] :
    # This user is a viewer
但是如何检查多个用户类型/PK?我想做点像

# This won't work
if [ 6, 7, 8 ] in [ user_type.pk for user_type in user.profile.user_types.all() ] :
    # This user is either a viewer, moderator, or administrator
我的列表理解方法也是检查
用户类型的
Django方式的?看起来不是这样,但我不知道如何在Django中干净地查询它

欢迎任何提示和建议。提前谢谢

编辑:

我刚刚发现我可以用更Django的方式列出PK

我还发现我可以像这样检查多个值

if len( set( [ 1, 9 ] ).intersection( set( user_types ) ) )
    # True because of 1 is in user_types (don't care about 9)

if len( set( [ 4, 99 ] ).intersection( set( user_types ) ) )
    # False because 4 nor 99 is in user_types
但是,即使是这个
set
方法似乎也不太友好。一定有更简单的方法,对吗?

只要做:

def has_roles(user, roles):
    return user.profile.user_types.filter(pk__in=roles).count() == len(roles)

print has_roles(user, [6,7,8])
另外,我会避免使用硬编码的PK ID号作为您的标识符。太多的事情可能会出问题。而是在运行时定义映射并按名称引用它们。多方面都会有所改善:

  • 您的代码将更易于阅读
  • Django将卸载与DB匹配的模型实例作为第一项
  • 从那时起,您可以缓存ID,而不再询问DB
然后你可以做:

class UserType( models.Model ):
    TYPES = (( 'tenant', 'Tenant'),
             ( 'propman', 'Property Manager'),
             ( 'propown', 'Property Owner'),
             ( 'vendman', 'Vendor Manager'),
             ( 'vendor', 'Vendor'),
             ( 'viewer', 'Viewer'),
             ( 'moderator', 'Moderator'),
             ( 'admin', 'Administrator'))

    name = models.CharField( max_length = 135, choices=TYPES )

def has_role(user, role):
    return user.profile.user_types.filter(name=role).count() == 1

def has_roles(user, roles):
    return user.profile.user_types.filter(name__in=roles).count() == len(roles)

print has_roles(user, ['viewer','moderator','admin'])
最后,您可以将上述两个函数添加到:

class UserProfile( models.Model ) :
    user       = models.OneToOneField( User )
    user_types = models.ManyToManyField( UserType, null = True, blank = True )


    def has_role(self, role):
        return self.user_types.filter(name=role).count() == 1

    def has_roles(self, roles):
        return self.user_types.filter(name__in=roles).count() == len(roles)
然后在将来像这样使用它:

u = User.objects.get(username='me')
if u.userprofile.has_role('admin'):
    print 'I have the powah!'

很棒的思路!我绝对同意你的方法更干净更简单。谢谢!一点评论:我不确定是否遵循您的
是否具有
函数。为什么要将其设置为
==len(角色)
?例如,
用户
一直是
查看者
主持人
,和
管理员
(与所需的OR逻辑相反)?不管怎样,我决定使用你的函数
has_roles()
处理所有事情,而忽略
==len(角色)
。现在它的工作方式正是我想要的。再次感谢!这只是对数据库的优化。如果执行此操作,则.count()DB只需计算行数,它不必获取角色的名称,python也不必构造
UserType
对象。两者的区别确实是或对和。没有
.count()==len(角色)
它的等价物或逻辑(用户具有任何这些角色),有了len(角色),它的等价物user具有所有这些角色。干杯
u = User.objects.get(username='me')
if u.userprofile.has_role('admin'):
    print 'I have the powah!'