2017-10-19 10 views
1

私は、App Engine上で実行しているデータサーバにndbを使用しています。デコレータ実装によるデータベースモデルのクロストーク

@acl 
class MyModel(ndb.Model): 
    ... 
    access_control = ndb.JsonProperty(default={}) 

私はいくつかのアクセス制御方法で私のモデルを強化するために@aclデコレータを使用します。

データ・モデルは、次のようになります。 デコレータこのようなものになります。

def acl(model): 
    def grant(self, subject, credentials): 
     logging.debug("ACL before: {}".format(self.access_control)) 
     self.access_control[subject] = { ... } # Set correct value. 
     logging.debug("ACL after: {}".format(self.access_control)) 
    model.grant = grant 
    ... 
... 

私のアプリケーションからは、その後、私はこのようにそれを呼び出すことを期待する:

>>> mdl = MyModel(...) 
>>> mdl.grant("someone", "creds") 
ACL before: {} 
ACL after: { < properly populated access_control > } 

をしかし、その代わりに、私はこれに似た何かを得る:

>>> mdl1 = MyModel(...) 
>>> mdl1.grant("someone", "creds") 
ACL before: {} 
ACL after: { < properly populated access_control > } 

>>> mdl2 = MyModel(...) 
>>> mdl2.grant("someone else", "other creds") 
ACL before: { < values from mdl1 > } 
ACL after: { < values from mdl1 concatenated with mdl2 > } 

このバグは、grant()機能のselfが何とかグローバル値のように機能していると思わせています。これらの呼び出しが異なるインスタンスで実行されても、以前の呼び出しのデータが蓄積されているため、 です。

質問は:なぜ私のモデルはそれらの間にデータを読み込んでいますか? selfはデコレータの文脈で、クラスメソッドの文脈ではselfと同じですか?

答えて

0

モデルプロパティは静的要素です。 correct way to define class variables in Pythonも参照してください。

クラスデコレータが存在すると、通常はプロパティ値の適切な初期化を処理するndb内部からの通常の操作が妨げられている可能性があります。

私はクラスデコレータにはあまりよく慣れていないので、修正されたデコレータでこれをどう対処できるかはわかりません。たぶんこのようなもの(明示的にプロパティを初期化する)?

def acl(model): 
    def grant(self, subject, credentials): 
     self.access_control = {} # Always start with the default value 
     logging.debug("ACL before: {}".format(self.access_control)) 
     self.access_control[subject] = { ... } # Set correct value. 
     logging.debug("ACL after: {}".format(self.access_control)) 
    model.grant = grant 

私は同様の機能を実現するために選んだ(私見簡単に理解するために)解決策ではなく、デコレーターのプレーンなクラスの継承を使用する(ただし、値の同じリセットを注意してください)した:

class ACLModel(ndb.Model): 
    access_control = ndb.JsonProperty(default={}) 

    def grant(self, subject, credentials): 
     self.access_control = {} 
     self.access_control[subject] = { ... } # Set correct value. 

class MyModel(ACLModel): 
    ... 
    # other specific properties 

継承メソッドを使用すると、複数のモデルで同じアクセス制御コード(自己完結型)を簡単に使用できます。デコレータメソッドでは、使用可能なモデルの追加要件があります。すべてにはaccess_controlプロパティを持つが必要です(自己完結型ではありません)。

関連する問題