2010-02-22 5 views
6

these proposed signal decorators과 같은 작업을하려고합니다. 장식 된 메서드를 신호 (데코레이터의 인수로 신호의 보낸 사람)와 연결하는 데코레이터가있는 것 외에도 클래스 메서드에 데코레이터를 사용하고 싶습니다.Django 신호를 통한 모델 메서드의 데코레이터?

내가 지금처럼 장식 사용하려면 :

class ModelA(Model): 

    @connect.post_save(ModelB) 
    @classmethod 
    def observe_model_b_saved(cls, sender, instance, created, **kwargs): 
     # do some stuff 
     pass 

데코레이터는 : 나는이 작업을 수행 할 때

from django.db.models import signals 
def post_save(sender): 
    def decorator(view): 
     signals.post_save.connect(sender=sender, receiver=view) 
     return view 
    return decorator 

내가 오류는 다음과 같습니다

 
File "/Library/Python/2.6/site-packages//lib/python2.6/site-packages/django/dispatch/dispatcher.py", line 78, in connect 
AssertionError: Signal receivers must be callable. 

문제는 @classmethod이 호출 할 수없는 클래스 메서드 객체를 반환한다는 것입니다. classmethod이 실제로 어떻게 작동하는지 이해할 수 없지만 클래스 메소드 객체가 클래스에서 액세스 될 때까지 (예 : ModelA.observe_model_b_saved) 클래스 메소드 객체가 호출 가능 객체로 변환되지 않았다고 this reference page에서 추측합니다. (1) 내 메서드를 모델의 클래스 또는 인스턴스 메서드로 정의 할 수 있고 (2) 메서드 정의에 데코레이터를 직접 사용하여 신호에 연결할 수있는 방법이 있습니까? 감사!

+0

@classmethod와 @connect의 순서를 바꾸면 작동합니까? – Wogan

+0

아니요 이제 알게되었습니다 : "observe_model_b_saved()는 정확히 4 개의 비 키워드 인수 (주어진 0 개)"를가집니다. 무슨 뜻이에요? –

답변

2

예제 코드에서는 명확하지 않으므로 신호 수신기가 실제로 @classmethod이어야하는지 묻고 싶습니다. 나는. 정기적 인 방법을 사용합니까 (그리고 여전히 클래스 자체에 액세스해야한다면 self.__class__을 사용하십시오)? 방법이 필요합니까 (함수를 사용할 수 있습니까?)?

class ModelA(Model): 

    @classmethod 
    def do_observe_model_b_saved(cls, sender, instance, created, **kwargs): 
     # do some stuff 
     pass 

    @connect.post_save(ModelB) 
    def observe_model_b_saved(self, sender, instance, created, **kwargs): 
     self.do_observe_model_b_saved(sender, instance, created, **kwargs) 
+0

감사합니다. 누군가이 질문의 다른 버전 인 클래스 데코레이터에 제안한 해결책을 생각해 보겠습니다. 클래스 데코레이터는 전체 클래스로드가 완료된 후 신호 연결을 만들 수 있으므로 클래스 메서드에 직접 액세스 할 수 없다는 문제를 해결할 수 있습니다. http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class –

1

당신은 그것을 대신 @staticmethod 만들 수 없습니다 :

또 다른 옵션은 신호 듣고 @classmethod에 전화를 위임하는 두 번째 방법을 사용할 수 있습니다? 그렇게하면 데코레이터의 순서를 바꿀 수 있습니다.

class ModelA(Model): 

    @staticmethod 
    @connect.post_save(ModelB) 
    def observe_model_b_saved(sender, instance, created, **kwargs): 
     # do some stuff 
     pass 

대신 CLS 인수를 전달하기의 전체 이름으로 클래스를 참조해야 할 것이다, 그러나 이것은 당신이 유사한 코드 구성을 유지 할 수있다.

+0

고맙지 만 그 해결책은 나를 위해 작동하지 않을 것입니다. 아마도 오버로드 된 멤버를 검색하기 위해 클래스에 동적으로 액세스해야합니다. 예 : 수퍼 클래스는 일부 특성에 의존하는 메서드를 정의하지만 하위 클래스는 특성을 오버로드합니다. 나는 overloaded 속성이 필요하고 명시 적으로 클래스의 이름을 지정함으로써 오는 속성이 필요하지 않습니다. –

0

매트의 대답을 바탕으로, @staticmethod 트릭이 저에게 효과적이었습니다. 문자열을 사용하여 구체적이지 않은 모델을 참조 할 수 있습니다.

class Foo(Model): 

    @staticmethod 
    @receiver(models.signals.post_save, sender='someappname.Foo') 
    def post_save(sender, instance, created, **kwargs): 
      print 'IN POST SAVE', sender, instance.id, created