2017-05-10 38 views
11

我在我的Django項目中創建了一個裝飾器,以將參數值插入裝飾方法的參數。在基於Django類的視圖中檢查視圖方法參數名稱

我通過使用inspect.getargspec來檢查方法中存在哪些參數並將它們放置在kwargs中。否則,由於方法中參數的數量不正確,我會得到一個錯誤。

雖然這在單獨的視圖方法中正常工作,但它涉及到Django的基於類的視圖時會失敗。

我相信這可能是因爲裝修使用@method_decorator在類級別的dispatch方法而不是個別getpost方法施用。

我是一個蟒蛇新手,可能會忽略這裏明顯的東西。

有沒有更好的方式來做我在做什麼?是否有可能在基於類的視圖中獲取方法參數名稱?

我使用Python 2.7和1.11的Django

的裝飾

def need_jwt_verification(decorated_function): 
    @wraps(decorated_function) 
    def decorator(*args, **kwargs): 
     request = args[0] 
     if not isinstance(request, HttpRequest): 
      raise RuntimeError(
       "This decorator can only work with django view methods accepting a HTTPRequest as the first parameter") 

     if AUTHORIZATION_HEADER_NAME not in request.META: 
      return HttpResponse("Missing authentication header", status=401) 

     jwt_token = request.META[AUTHORIZATION_HEADER_NAME].replace(BEARER_METHOD_TEXT, "") 

     try: 
      decoded_payload = jwt_service.verify_token(jwt_token) 

      parameter_names = inspect.getargspec(decorated_function).args 

      if "phone_number" in parameter_names or "phone_number" in parameter_names: 
       kwargs["phone_number"] = decoded_payload["phone"] 
      if "user_id" in parameter_names: 
       kwargs["user_id"] = decoded_payload["user_id"] 
      if "email" in parameter_names: 
       kwargs["email"] = decoded_payload["email"] 

      return decorated_function(*args, **kwargs) 
     except JWTError as e: 
      return HttpResponse("Incorrect or expired authentication header", status=401) 

    return decorator 
基於

類視圖

@method_decorator([csrf_exempt, need_jwt_verification], name="dispatch") 
class EMController(View): 
    def get(self, request, phone_number, event_id): 
     data = get_data() 

     return JsonResponse(data, safe=False) 

    def post(self, request, phone_number, event_id): 


     return JsonResponse("Operation successful", safe=False) 

編輯:

施加裝飾的明顯的解決方案在方法級別,不適用於Django的基於類的視圖。您需要在url配置中應用裝飾器或將裝飾器應用於調度方法。

編輯: 我已經發布了與我正在探索的解決方法相關的代碼,將參數名稱作爲參數傳遞給裝飾器。

+0

發佈您正在面臨問題的代碼 – Exprator

+0

我不認爲它會有太大用處。但確定... – Thihara

+0

我試過你的代碼,它工作完美!那麼,你能給出一些細節嗎? – gushitong

回答

1

我理想中的圖書館的現狀似乎是不可能的。所以,這就是我最終的結局。

  parameter_names = inspect.getargspec(decorated_function).args 

      if "phone_number" in parameter_names or "phone_number" in injectables: 
       kwargs["phone_number"] = decoded_payload["phone"] 
      if "user_id" in parameter_names: 
       kwargs["user_id"] = decoded_payload["user_id"] 
      if "email" in parameter_names: 
       kwargs["email"] = decoded_payload["email"] 

      request.__setattr__("JWT", {}) 
      request.JWT["phone_number"] = decoded_payload["phone"] 
      request.JWT["user_id"] = decoded_payload["user_id"] 
      request.JWT["email"] = decoded_payload["email"] 

這個修飾器會自動在基於方法的視圖中填充參數。

但它也會將JWT屬性注入要使用的基於類的視圖的請求對象。像request.GETrequest.POST

5

我發現這個職位:Function decorators with parameters on a class based view in Django

可以提供回答您的問題:

如果你想傳遞一個帶參數的裝飾,你只需要:

  • 評估裝飾器創建者函數中的參數。

  • 將評估值傳遞給@method_decorator

上面提到的和考慮下鏈接的答案提供的代碼,你應該:

injectables=[inject_1, inject_2, ..., inject_n] 
decorators = [csrf_exempt, need_jwt_verification(injectables)] 

@method_decorator(decorators, name="dispatch") 
class EMController(View): 
    ... 


離開我以前誤認爲答案在這裏遺留原因,不要嘗試這在家裏(或任何地方,在Django,爲此!)

如果我們觀察"decorating a class"文檔中,我們可以看到以下內容:

或者,更簡潔,你可以裝飾類,而不是和傳遞方法的名稱將被裝飾成關鍵詞參數名:

所以,你必須改變你的@method_decoratorname參數匹配,將適用於上述方法:

decorators = [csrf_exempt, need_jwt_verification(injectables=[])] 

@method_decorator(decorators, name='get') 
@method_decorator(decorators, name='post') 
class EMController(View): 

個人而言,我更喜歡把我的具體方法的頂部裝飾,他們將適用於:

class EMController(View): 
    @method_decorator(decorators) 
    def get(self, request, phone_number, event_id): 
     ... 

    @method_decorator(decorators)  
    def post(self, request, phone_number, event_id): 
     ... 

+0

感謝您的回答,但是它不能像Django的基於類的視圖那樣工作。你不能在方法級應用裝飾器。他們需要應用於'dispatch'方法。 – Thihara

+0

@Thihara我找到了一個可能的答案,通過搜索,我編輯了我的答案,看看! –

+0

將參數傳遞給裝飾者也是我的最後手段,但我會非常喜歡檢測參數名稱的黑魔法方式:) – Thihara