Python 检查Django中M2M关系中的多个值
在英语中,我想检查用户的类型是查看器、版主还是管理员 以下是myPython 检查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
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!'