2014-12-03 31 views
1

我正在使用我的django應用程序模型Player創建一個新模型,其中包含當前現有模型的所有字段

class Player(models.Model): 
    """ player model """ 
    name = models.CharField(max_length=100, null=True, blank=True) 
    date_created = models.DateTimeField(auto_now_add=True) 
    last_updated = models.DateTimeField(auto_now=True) 
    hash = models.CharField(max_length=128, null=True, blank=True) 
    bookmark_url = models.CharField(max_length=300, null=True, blank=True) 

按我的要求,我需要建立一個新的模式BookmarkPlayer這將有Player模型的各個領域。

現在我有兩件事情在我的腦海裏這樣做。

  1. 我可以爲BookmarkPlayer模型擴展Player類。
 
    class BookmarkPlayer(Player): 
     """ just a bookmark player""" 
     class Meta: 
      app_label = "core" 
  • 我可以定義成BookmarkPlayer模型播放器模型的所有字段。
  •  
        class BookmarkPlayer(models.Model): 
          """ bookmark player model """ 
          name = models.CharField(max_length=100, null=True, blank=True) 
          date_created = models.DateTimeField(auto_now_add=True) 
          last_updated = models.DateTimeField(auto_now=True) 
          hash = models.CharField(max_length=128, null=True, blank=True) 
          bookmark_url = models.CharField(max_length=300, null=True, blank=True) 
    

    我只是想知道哪種方式是更好地做到這一點。請分享給我的,如果有另一種好辦法。

    更新問題

    Knbb的主意,以創建一個基類是有趣的,但我面臨的問題,我的模型,該模型已存在導入數據庫之一。

    我的實際型號:更改後

     
    class Address(models.Model): 
        address = models.TextField(null=True, blank=True) 
    
    
    class Site(models.Model): 
        domain = models.CharField(max_length=200) 
    
    
    class Player(models.Model): 
        # ... other fields 
        shipping_address = models.ForeignKey(Address, related_name='shipping') 
        billing_address = models.ForeignKey(Address, related_name='billing') 
        created_at = models.DateTimeField(auto_now_add=True) 
        updated_at = models.DateTimeField(auto_now_add=True) 
        site = models.ManyToManyField(Site, null=True, blank=True) 
    
        class Meta: 
         abstract = True 
    

    型號:

     
    class Address(models.Model): 
        address = models.TextField(null=True, blank=True) 
    
    
    class Site(models.Model): 
        domain = models.CharField(max_length=200) 
    
    
    class BasePlayer(models.Model): 
        # .. other fields 
        shipping_address = models.ForeignKey(Address, related_name='shipping') 
        billing_address = models.ForeignKey(Address, related_name='billing') 
        created_at = models.DateTimeField(auto_now_add=True) 
        updated_at = models.DateTimeField(auto_now_add=True) 
        site = models.ManyToManyField(Site, null=True, blank=True) 
    
        class Meta: 
         abstract = True 
    
    class Player(BasePlayer): 
        class Meta: 
         app_label = 'core' 
    
    
    class BookmarkPlayer(BasePlayer): 
        class Meta: 
         app_label = 'core' 
    
    

    當我運行我的Django的服務器我得到如下的錯誤了這些改變後。

     
    django.core.management.base.CommandError: One or more models did not validate: 
    core.test1: Accessor for field 'shipping_address' clashes with related field 'Address.shipping'. Add a related_name argument to the definition for 'shipping_address'. 
    core.test1: Reverse query name for field 'shipping_address' clashes with related field 'Address.shipping'. Add a related_name argument to the definition for 'shipping_address'. 
    core.test1: Accessor for field 'billing_address' clashes with related field 'Address.billing'. Add a related_name argument to the definition for 'billing_address'. 
    core.test1: Reverse query name for field 'billing_address' clashes with related field 'Address.billing'. Add a related_name argument to the definition for 'billing_address'. 
    core.test2: Accessor for field 'shipping_address' clashes with related field 'Address.shipping'. Add a related_name argument to the definition for 'shipping_address'. 
    core.test2: Reverse query name for field 'shipping_address' clashes with related field 'Address.shipping'. Add a related_name argument to the definition for 'shipping_address'. 
    core.test2: Accessor for field 'billing_address' clashes with related field 'Address.billing'. Add a related_name argument to the definition for 'billing_address'. 
    core.test2: Reverse query name for field 'billing_address' clashes with related field 'Address.billing'. Add a related_name argument to the definition for 'billing_address' 
    

    答:
    最後我得到的回答,如果我們正在使用一個ForeignKey或ManyToManyField的related_name屬性爲抽象模型。
    這通常會導致抽象基類中的問題,因爲此類中的字段包含在每個子類中,每次屬性(包括related_name)的值完全相同。
    要解決此問題,當您在抽象基類(僅)中使用related_name時,部分名稱應包含'%(app_label)s'和'%(class)s'。
    https://docs.djangoproject.com/en/dev/topics/db/models/#abstract-base-classes
    現在我BasePlayer模型

     
    class BasePlayer(models.Model): 
        # .. other fields 
        shipping_address = models.ForeignKey(Address, related_name='%(app_label)s_%(class)s_shipping') 
        billing_address = models.ForeignKey(Address, related_name='%(app_label)s_%(class)s_billing') 
        created_at = models.DateTimeField(auto_now_add=True) 
        updated_at = models.DateTimeField(auto_now_add=True) 
        site = models.ManyToManyField(Site, null=True, blank=True) 
    
        class Meta: 
         abstract = True 
    
    +0

    還有其他幾種更好的方法可以做到這一點,但這取決於您的確切要求,哪一個最好。首先你想要兩個模型的原因是什麼? – knbk 2014-12-03 12:54:25

    +0

    我想爲播放器的詳細信息添加書籤,以便我可以在我的網站上分享用戶之間的會話。 – 2014-12-03 13:11:53

    +1

    因此,如果我理解正確,您基本上想要在特定時刻複製'Player'的詳細信息並將其另存爲BookmarkPlayer?在那種情況下,看到我的答案,那將是最好的方法。添加一些便利方法來將'Player'轉換爲'BookmarkPlayer'也很容易,反之亦然。 – knbk 2014-12-03 13:16:33

    回答

    5

    如果您BookmarkPlayer需要同樣的數據,但在不同的表,抽象基地模式是最好的一段路要走:

    class BasePlayer(models.Model): 
        name = models.CharField(max_length=100, null=True, blank=True) 
        date_created = models.DateTimeField(auto_now_add=True) 
        last_updated = models.DateTimeField(auto_now=True) 
        hash = models.CharField(max_length=128, null=True, blank=True) 
        bookmark_url = models.CharField(max_length=300, null=True, blank=True) 
    
        class Meta: 
         abstract = True 
    
    class Player(BasePlayer): 
        """ player model """ 
        pass 
    
    class BookmarkPlayer(BasePlayer): 
        """ bookmark player model """ 
        pass 
    

    這樣一來,既PlayerBookmarkPlayer繼承了BasePlayer模型中的領域,但由於BasePlayer是抽象的,該模型是完全解耦的。

    在另一方面,多表繼承仍保存字段一個表,但是有一個隱含的OneToOneField添加額外的表爲BookmarkPlayerPlayer表。

    +0

    我試着按照你的建議創建一個抽象性質的基類,但通過使用這個我不能驗證我的模型。請參閱更新的問題 – 2014-12-04 08:51:56

    0

    大約有模型繼承這裏一些好的信息: https://docs.djangoproject.com/en/1.7/topics/db/models/#model-inheritance

    選項2將引入重複,這始終是壞的。如果BookmarkPlayer不會有任何新字段,只有不同的方法,我建議您使用鏈接中描述的「代理模型」選項,因爲您不需要BookmarkPlayer在數據庫中擁有自己的表。

    如果它需要它自己的表,「多表inhertiance」是的路要走,這將是選項1你的問題

    +0

    BookmarkPlayer需要將其自己的表放入數據庫。 – 2014-12-03 13:07:12

    +1

    @PrashantGaur我更新了覆蓋該場景的答案 – maillard 2014-12-03 13:10:16

    +1

    @knbk當然是對的,多表繼承將只保存額外的'BookmarkPlayer'字段在一個新表中。他的回答更好:) – maillard 2014-12-03 13:25:56

    相關問題