2009-09-23 8 views
8

Djangoモデルの行ベースのセキュリティチェックを実装しようとしています。私がモデルマネージャにアクセスするとき、データベースクエリで使用されるいくつかの追加情報を指定して、許可されたインスタンスだけがデータベースからフェッチされるという考えがあります。Djangoモデル - マネージャに追加情報を渡す

たとえば、ユーザーとアイテムという2つのモデルがあります。各アイテムはあるユーザに属し、ユーザは多くのアイテムに接続することができる。また、ユーザーに別のユーザーのアイテムが表示されたり表示されたりしないようにするための制限がいくつかあります。私は次のよう作られ、このacheiveするに

items = Item.scoped.forceRule('user1').all() # all items visible for 'user1' 

または

# show all items of 'user2' visible by 'user1' 
items = Item.scoped.forceRule('user1').filter(author__username__exact = 'user2') 

:私は他のクエリ要素からこの制限を分離し、のようなものを書きたい示す例については

class SecurityManager(models.Manager): 

    def forceRule(self, onBehalf) : 
     modelSecurityScope = getattr(self.model, 'securityScope', None) 
     if modelSecurityScope : 
      return super(SecurityManager, self).get_query_set().filter(self.model.securityScope(onBehalf)) 
     else : 
      return super(SecurityManager, self).get_query_set() 

    def get_query_set(self) : 
     # 
     # I need to know that 'onBehalf' parameter here 
     # 
     return super(SecurityManager, self).get_query_set() 

class User(models.Model) : 
    username = models.CharField(max_length=32, unique=True) 

class Item(models.Model) : 
    author = models.ForeignKey(User) 
    private = models.BooleanField() 
    name = models.CharField(max_length=32) 

    scoped = SecurityManager() 

    @staticmethod 
    def securityScope(onBehalf) : 
     return Q(author__username__exact = onBehalf) | Q(bookmark__private__exact = False) 

をそれが正常に動作しますしかし、以下では死ぬ:

items = Item.scoped.forceRule('user1').filter(author__username__exact = 'user2') # (*) 
items2 = items[0].author.item_set.all() # (**) 

確かに、items2には、ルールに適合するものだけでなく、 'user2'のすべての項目が設定されます。これは、all()が実行されたときに、SecurityManager.get_query_set()に制限セットに関する情報がないためです。それは可能ですが。たとえば、forceRule()では、すべてのインスタンスにフィールドを追加し、マネージャからそのフィールドにアクセスできる場合は、必要なルールを適用できます。

したがって、(**)という文で呼び出された(*)という文のforceRule()に与えられた引数をマネージャに渡す方法はありますか?

他の質問 - 私はまったくやってはいけない奇妙なことをしていますか?

ありがとうございます。

+0

私も同じユースケースに直面していますが、どうやってこれを回避できたのでしょうか?ありがとう! – ultrajohn

答えて

4

私は2つの問題があると思うのドキュメントの私の読書から:

  1. SecurityManagerが関連するオブジェクトのために使用されることはありません(とdjango.db.models.Managerのインスタンスが代わりに使用されますが)
  2. 上記を修正することができますが、ドキュメントでは、lengthsに進み、get_query_set()が関連するクエリの行を除外しないように指定しています。

QuerySetを使用して必要なフィルタを適用する関数を作成することをお勧めします。これは、アイテムのQSを取得してさらに処理したい場合に使用できます。

+0

ありがとうございました。 1.ドキュメントを読んで、 'items [0] .author.item_set.all()'中にDjangoがSecurityManager.get_query_set()を呼び出したときに非常に驚いていました。私はuse_for_related_fieldsでそれらを尋ねなかった。しかし、それはモデルの唯一のマネージャーでした、多分それは重要です。 2.はい、私はそれを読んだけど、それでも私の場合ではないと思っています。なぜなら、私はDjangoがすべてのデータベースを見るのではなく、その一部を見たいからです。 おそらく、私はあなたの提案のように何とかしますが、私の質問は、無関係なデータをどのようにフィルタリングするかではなく、このフィルタリングをできるだけ簡単かつ自動化することです。 –

関連する問題