2014-04-11 51 views
0

我有以下代碼:如何繼承RequestHandler以自動驗證參數?

class CounterIDHandler(RequestHandler): 
    @gen.coroutine 
    def get(self, counter_id): 
     try: 
      object_id = bson.objectid.ObjectId(counter_id) 
     except bson.errors.InvalidId as e: 
      self.finish(json_encode({'e': str(e)})) 
      return 
      # I want to finish execution here 

class CounterHandler(CounterIDHandler): 
    @gen.coroutine 
    def get(self, counter_id): 
     super().get(counter_id) 
     print("this should not print if we get exception in super().get") 
     try: 
      # I want to use object_id here 
     except Exception as e: 
      self.finish(json_encode({'e': str(e)})) 

這顯然是行不通的,但它顯示了什麼,我試圖做的。 self.finish()終止與客戶端的連接,但不會終止執行。

我想驗證counter_id是一個有效的object_id而無需在所有處理程序中複製粘貼代碼。

回答

1

爲什麼你把它放在基類中的get()?它看起來像這樣應該在一個單獨的get_object_id方法。在任何情況下,共享方法都有兩種方式影響調用者:異常和返回值。

使用無的返回值的信號,來電者應停止:

class CounterIDHandler(RequestHandler): 
    def get_object_id(self, counter_id): 
     try: 
      return bson.objectid.ObjectId(counter_id) 
     except bson.errors.InvalidId as e: 
      self.finish(json_encode({'e': str(e)})) 
      return None 

class CounterHandler(CounterIDHandler): 
    def get(self, counter_id): 
     object_id = self.get_object_id(counter_id) 
     if object_id is None: 
      return 

還是有例外和write_error處理程序:

class CounterIDHandler(RequestHandler): 
    def get_object_id(self, counter_id): 
     return bson.objectid.ObjectId(counter_id) 

    def write_error(self, status_code, **kwargs): 
     if 'exc_info' in kwargs: 
      typ, exc, tb = kwargs['exc_info'] 
      if isinstance(exc, bson.errors.InvalidId): 
       self.finish(json_encode({'e': str(e)})) 
       return 
     super(CounterIDHandler, self).write_error(status_code, **kwargs) 

class CounterHandler(CounterIDHandler): 
    def get(self, counter_id): 
     object_id = self.get_object_id() 
2

你可以做一個裝飾,這樣的事情(未經測試):

def oid_validator(f): 
    @web.asynchronous 
    def wrapped(self, oid_str): 
     try: 
      oid = bson.objectid.ObjectId(oid_str) 
     except bson.errors.InvalidId as e: 
      self.finish(json_encode({'e': str(e)})) 
     else: 
      coro = gen.coroutine(f) 
      coro(self, oid) 

然後,而不是裝飾你的get()種方法與@gen.coroutine,你可以用@oid_validator裝飾一番:

class CounterIDHandler(RequestHandler): 
    @oid_validator 
    def get(self, counter_id): 
     # counter_id is now an ObjectId instance 
+0

真是太爽瞭解決方案,我認爲這是很一般的,你可以用它每次你需要驗證,但在這種情況下,我想本的更好的解決方案。 – ragezor