2011-06-17 79 views
4

在我們使用Django開發的應用程序中,在某些情況下,我們需要爲具有所有者的某些模型的用戶自動分配權限(對於字段名稱沒有規則可以是「用戶」,「所有者」,「教練」等,也可以有多個字段。)我的解決方案是創建一個包含這些字段名稱的裝飾器,這將放在模型定義之前,像這樣在樣本)使用特定的Django代碼:Python - 使類裝飾器在派生類上工作

@auto_assign_perms('owner', 'user') 
class Test(Base): 
    pass 

讓我們假設Base是Django的Model類,在這裏我想補充的功能對象被保存後分配權限後一個抽象類派生。現在我只打印分配給班級的用戶列表。下面你可以找到裝飾代碼和Base類:

class auto_assign_perms(object): 
    def __init__(self, *users): 
     self.users = users 

    def __call__(self, cls): 
     cls.owners.update(self.users) 
     return cls 


class Base(object): 
    owners = set() 

    def save(self, *args, **kwargs): 
     for owner in self.owners: 
      print owner, 
     print 

而且我的模型看起來是這樣的:

@auto_assign_perms('owner', 'user') 
class Test(Base): 
    pass 

@auto_assign_perms('coach') 
class Test2(Base): 
    pass 

的問題是,這兩個子類包含所有三個字段('owner', 'user', 'coach'),altough print self.__class__.__name__Base.save()方法正確顯示「Test」或「Test2」。我試圖在Base類中添加classmethod get_owners(),然後迭代其結果,但它沒有幫助。 我該如何解決這個問題?也許我應該使用元類(我還沒有得到它們)?提前致謝。

回答

4

你需要設置所有者的列表,而不是更新:

class auto_assign_perms(object): 
    def __init__(self, *users): 
     self.users = users 

    def __call__(self, cls): 
     cls.owners = set(self.users) # <- here 
     return cls 

#some tests 
@auto_assign_perms('owner', 'user') 
class Test(Base): 
    pass 

@auto_assign_perms('coach') 
class Test2(Base): 
    pass 


t = Test() 
t.save() 
t = Test2() 
t.save() 

>>> 
owner user 
coach 
+0

我的解決方案與您的類似,唯一的區別是,在執行'cls.owners = set(..)'時,將會在派生類中動態創建一個新的類變量'owners',並且'Base.owners'將不會改變這是國際海事組織哈克,因爲1)大多數用戶不會期待和2)'Base.owners'是無用的,但很好的答案無論如何:) – mouad 2011-06-17 09:27:35

+1

@mouad而且你將不得不重複行'owner = set()'並再次在每個孩子班上。不是很乾。所以這就是'Base.owners'的用法 - 定義它並繼承。 – DrTyrsa 2011-06-17 09:31:02

+0

它的工作原理,非常感謝!編程是一個域,您可以查看您的代碼幾個小時,無法看到錯誤或解決方案,並且另一個人可以立即看到它:) – uolot 2011-06-17 09:33:56

1

您正在使用owners作爲Base的類變量,所以無論何時更改owners,所有派生類中都會看到更改。

爲了解決這個問題,你應該定義owners變量作爲派生類的類變量:

class Base(object): 

    def save(self, *args, **kwargs): 
     for owner in self.owners: 
      print owner, 
     print 

@auto_assign_perms('owner', 'user') 
class Test(Base): 
    owners = set() 

@auto_assign_perms('coach') 
class Test2(Base): 
    owners = set() 
+0

[你確定](http://pastebin.com/154Pmg86)? – DrTyrsa 2011-06-17 09:24:17

0

叫我偏執狂但我覺得這個解決方案更優雅,因爲我不認爲你需要所有者成爲一個類變量:

def auto_assign_perms(*users): 

    def class_wrapper(cls): 
     class ClassWrapper(cls): 
      def __init__(self, owners=users): 
       super(cls, self).__init__(owners=owners) 

     ClassWrapper.__name__ = cls.__name__ 
     ClassWrapper.__module__ = cls.__module__ 

     return ClassWrapper 

    return class_wrapper 


class Base(object): 
    def __init__(self, owners=None): 
     if owners is None: 
      owners = set() 
     self.owners = owners 

    def save(self, *args, **kwargs): 
     for owner in self.owners: 
      print owner, 
     print 


@auto_assign_perms('owner', 'user') 
class Test1(Base): 
    pass 


@auto_assign_perms('coach') 
class Test2(Base): 
    pass 


class Test3(Base): 
    pass 


t = Test1(); t.save() # owner user 
t = Test2(); t.save() # coach 
t = Test3(); t.save() #