Reputation: 30238
In English, I want to check whether a user's type is either a viewer, a moderator, or an administrator.
Here is the relevant part of 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 )
By the way, I set user.profile
to be the same thing as user.get_profile()
.
In my views.py
code, I want to do the checking. I figured out that
[ user_type.pk for user_type in user.profile.user_types.all() ]
will give me a list of pk
's for the user
's user_type
, like so [ 1, 2, 6 ]
. Meaning that this particular user is a tenant (1), property manager (2), and a viewer (6).
If I just want to check one user_type
, then I can simply do
if 6 in [ user_type.pk for user_type in user.profile.user_types.all() ] :
# This user is a viewer
But how can I check multiple user_types/pks? I wanted to do something like
# 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
Also is my method of list comprehension to check user_types
the Django-way? It doesn't seem like it, but I couldn't figure out how to query it cleanly in Django.
Any tips and suggestions welcomed. Thanks in advance!
EDIT:
I just figured out I can list pks the more Django-way with values_list
user_types = user.profile.user_types.values_list( 'pk', flat = True )
# [ 1, 2, 6 ]
I also figured out that I could check multiple values like this
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
But even this set
method doesn't seem very Django-friendly. There must be an easier way right?
Upvotes: 0
Views: 417
Reputation: 4346
Simply do:
def has_roles(user, roles):
return user.profile.user_types.filter(pk__in=roles).count() == len(roles)
print has_roles(user, [6,7,8])
P.S. I would shy away from using hard coded PK ID numbers as your identifiers. Too many things can go wrong with that. Instead define a mapping at runtime and reference them by names. Multiple things will improve:
Then you can do:
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'])
Finally, you can add the two functions above to:
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)
And then use it like this in the future:
u = User.objects.get(username='me')
if u.userprofile.has_role('admin'):
print 'I have the powah!'
Upvotes: 3