2012-04-08 13 views
0

英語では、ユーザーのタイプがビューア、モデレータ、または管理者のいずれかであるかどうかをチェックしたいと思います。DjangoのM2M関係で複数の値を確認する

がここにところで、私の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.get_profile()と同じものであることをuser.profileを設定します。

私のviews.pyコードでは、チェックしたいと思います。私は

[ user_type.pk for user_type in user.profile.user_types.all() ] 

はS user_type、のようなので、[ 1, 2, 6 ] 'はuserためs' は私にpkのリストを与えることを考え出しました。この特定のユーザがテナント(1)、プロパティマネージャ(2)、およびビューア(6)であることを意味します。

私はちょうど1 user_typeをチェックしたい場合は、私は単に

if 6 in [ user_type.pk for user_type in user.profile.user_types.all() ] : 
    # This user is a viewer 

を行うことができますしかし、どのように私は、複数のUSER_TYPES/PKSを確認することができますか?私は

# 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 

のようなものをやってみたかった。またuser_typesジャンゴウェイをチェックするリスト内包の私の方法ですか?それはそれのようには見えませんが、私はそれを照会する方法を理解できませんきれいにのDjango。

ご意見やご提案をお待ちしています。前もって感謝します!

EDIT:

私はちょうど私が私がまた私この

ようチェック複数の値ができたことを考え出し values_list

user_types = user.profile.user_types.values_list('pk', flat = True) 
# [ 1, 2, 6 ] 

でより多くのジャンゴウェイPKS一覧表示することができます考え出しました

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方法dドンゴに優しいとは思わない。より簡単な方法が必要でしょうか?

答えて

2

は単純に実行します。

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.を私はあなたの識別子としてハードコードされたPK ID番号を使用することを恥ずかしがります。あまりにも多くのことが間違って行くことができます。代わりに、実行時にマッピングを定義し、それらを名前で参照します。複数のものが改善されます:

  • あなたのコードは、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!' 
+0

思考の恐ろしい電車!私は間違いなくあなたの方法ははるかにクリーンでシンプルであることに同意します。どうもありがとう! – hobbes3

+0

1つのコメント:私はあなたの 'has_roles'関数に従っているかどうか分かりません。なぜそれを '== len(roles)'に設定していますか?例えば、 'user'が' viewer'、 'moderator'、* AND *' admin'(希望の* OR *論理に反対)という論理を意味していませんか? – hobbes3

+0

Nevermind、私はあなたの関数 'has_roles()'をすべてに使うことに決め、 '== len(roles)'を省略しました。今はそれが私が望むように機能します。再度、感謝します! – hobbes3

関連する問題