2017-01-27 30 views
2

我有一個需要受到它們保護的權限檢查和視圖的層次結構。例如,考慮這兩個檢查。撰寫適用於基於類的視圖的修飾器

def has_profile(user): 
    return user.profile is not None 

def is_a_sorcerer(user): 
    return user.profile.category == 'sorcerer' 

請注意,只有在用戶具有配置文件時調用is_a_sorcerer纔有意義。

對於任何有個人檔案的人來說,一些視圖應該是可以訪問的,一些視圖只能限制在巫師身上。

class ProfileView(View): 
    @method_decorator(user_passes_test(has_profile)) 
    def dispatch(self, *args, **kwargs): 
     return super().dispatch(*args, **kwargs) 

class SorcererView(ProfileView): 
    @method_decorator(user_passes_test(is_a_sorcerer)) 
    def dispatch(self, *args, **kwargs): 
     return super().dispatch(*args, **kwargs) 

但是,請注意,由於繼承,is_a_sorcererhas_profile之前調用和錯誤的。

有可能在is_a_sorcerer檢查has_profile

def is_a_sorcerer(user): 
    return has_profile(user) and user.profile.category == 'sorcerer' 

雖然這修正錯誤,會導致檢查has_profile兩次,有兩個以上的級別檢查的開銷迅速積累。

如何在不重複代碼的情況下編寫這些裝飾器?我仍然希望將權限檢查保留爲函數,以便可以將它們應用於基於函數的視圖。

+1

該繼承的問題是什麼?如果用戶沒有配置文件,它不能成爲魔術師,可以嗎? 在'is_a_sorcerer'實現中,你應該檢查'has_profile'是否也是。 – afilardo

+0

使用[權限](https://docs.djangoproject.com/zh/1.10/topics/auth/customizing/#custom-permissions)不是一個選項嗎? – afilardo

+0

將'permission_required'裝飾器添加到視圖與'user_passes_test'不會有區別,並且仍然需要兩次檢查權限。 – Koterpillar

回答

1

實際上,我只需在is_a_sorcerer方法中檢查has_profile。檢查has_profile兩次的開銷可以忽略不計。

def is_a_sorcerer(user): 
    return has_profile(user) and user.profile.category == 'sorcerer' 

可以避免運行兩次檢查,但我不認爲你能夠使用裝飾器。相反,您可以更改ProfileView,以便檢查測試列表。然後覆蓋子類中的測試列表。

class ProfileView(View): 
    user_tests = [has_profile] 

    def dispatch(self, *args, **kwargs): 
     for test_func in self.user_tests: 
      if not test_func(self.request.user): 
       return redirect('login') 
     return super().dispatch(*args, **kwargs) 


class SorcererView(ProfileView): 
    user_tests = ProfileView.user_tests + [is_a_sorcerer] 

請注意,這不太傳統,也許更脆弱/容易出錯。在子類中重寫user_tests時,很容易忘記包含ProfileView.user_tests

+0

實際上,裝飾器確實執行不一定被緩存的數據庫調用。 'user_tests'方法也是我在想的東西,可惜它不是默認的。 – Koterpillar

相關問題