2017-10-19 8 views
1

데이터 저장을 위해 ndb을 사용하는 App Engine에서 실행중인 웹 서버가 있습니다. 데코레이터 구현으로 인해 데이터베이스 모델에 대한 크로스 토크

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

내가 몇 가지 액세스 제어 방법과 내 모델을 확대하기 위해 @acl 장식을 사용

데이터 모델은 다음과 같이 보입니다. 데코레이터이 같은 같습니다

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

을하지만 그 대신 나는이 비슷한 얻을 : 내 응용 프로그램에서

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 
    ... 
... 

을, 그때 같이 호출 기대

>>> 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 내부에서 정상적인 작동을 방해 할 수 있습니다.

클래스 데코레이터에 익숙하지 않아 변형 된 데코레이터로 어떻게 해결할 수 있는지 확실하지 않습니다. 아마 뭔가 (명시 적으로 속성을 초기화하는) 뭔가?

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 

:

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 

나는 비슷한 기능을 달성하기 위해 뽑은 (이해하기 이럴 쉽게) 솔루션 대신 장식의 일반 클래스 상속을 사용 (하지만 값의 같은 재설정주의)했다 상속 방법을 사용하면 여러 모델에 대해 동일한 액세스 제어 코드 (자체 포함)를 쉽게 사용할 수 있습니다. 데코레이터 메소드는 사용할 수있는 모델에 대한 추가 요구 사항을 적용합니다. access_control 속성을 포함해야합니다 (자체 포함되지 않음).이 필요합니다.