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()
に与えられた引数をマネージャに渡す方法はありますか?
他の質問 - 私はまったくやってはいけない奇妙なことをしていますか?
ありがとうございます。
私も同じユースケースに直面していますが、どうやってこれを回避できたのでしょうか?ありがとう! – ultrajohn