2014-02-21 92 views
1

我對Django相當陌生,我試圖在Django模型中實現多態,但我看不到如何去做。在繼續之前,我不得不說我已經嘗試過django-model-utils和django-polymorphism,但它們並不完全符合我的要求。Django模型多態沒有多表繼承和額外的JOIN

我有一個叫播放器模式,每個玩家都有一個角色,每個角色都有不同的行爲(即他們的方法返回不同的值):

class Player(models.Model): 
    username=models.TextField() 
    role=models.ForeignKey(Role) #Role is another model with a field called ’name' 

    def allow_action(self) 
     #some stuff 

class RoleA(): 
    def allow_action(self): 
     #some specific stuff 

class RoleB(): 
    pass 

我想我每次檢索播放器的任何實例(在例子中通過Player.objects.filter(...)),每個實例都有由特定類(RoleA,RoleB等)內定義的自定義方法覆蓋的allow_action()方法,或者使用Player中提供的默認方法(如果相關的子類沒有使用相同名稱調用的方法(RoleA,RoleB等...是存儲在Player.role.name中的相同角色名稱)。

約束:

  1. 由於子類(RolaA,RoleB,等...),不增加新的領域,但只覆蓋方法,所有的數據必須存儲播放器的表裏面,所以我不希望使用Django多表繼承,但更類似於代理。

  2. 我不想執行額外的JOIN來確定特定的子類型,因爲所有需要的信息都存儲在播放器的表中。

我認爲這是一個標準的多態性模式,但我不明白如何使用同一個表的所有玩家(我已經實現了這個多態性,但沒有鏈接到一個Django模型來實現它在Django )。我見過Django有一種名爲「Proxy」的繼承,但它不允許像Player.objects.filter(...)那樣查詢,並且得到的方法被自定義方法覆蓋的實例(或者至少這是我所理解的)。

在此先感謝。

+0

爲什麼[django-polymorphic](https://django-polymorphic.readthedocs.org/en/latest/index.html)不符合您的需求?除非我錯過了某些東西,否則你可以完全按照你的意思去做。 – ptr

+0

@PeteTinkler根據這個[示例](https://django-polymorphic.readthedocs.org/en/latest/quickstart.html#making-your-models-polymorphic)它違反了我的第一個約束,即使用多表繼承會爲每個子類創建一個新表,但我不想要這些表,因爲我的數據庫會被未使用的表污染(我將擁有許多RoleA,RoleB,RoleC等)。我認爲這同樣適用於下面的代碼段。 – Sirion

+0

這些數據庫表將不會被使用。您將創建'RoleA ... RoleX'實例並使用'Role'基類中的'name'屬性。 – ptr

回答

0

免責聲明:我沒有用django-polymorphic,這個代碼是基於花在掃描文檔5分鐘,是完全未經測試,但我會感興趣,看看它是否工作:

from polymorphic import PolymorphicModel 


class Role(PolymorphicModel): 
    name = models.CharField() 


class RoleA(Role): 
    def allow_action(self): 
     # Some specific stuff... 


class RoleB(Role): 
    pass 


class Player(models.Model): 
    username=models.TextField() 
    role=models.ForeignKey(Role) #Role is another model with a field called ’name' 

    def allow_action(self) 
     if callable(getattr(self.role, "allow_action", None): 
      self.role.allow_action() 
     else: 
      # default action... 

現在我相信您應該能夠創建角色,角色A或角色B的實例,並在外鍵中指向它。在播放器實例上調用allow_action()將檢查Role(或RoleA,RoleB等)的實例是否具有可調用屬性allow_action(),如果是,則會使用該屬性,否則將使用默認值。