创建一个包含当前现有模型的所有字段的新模型

时间:2014-12-03 12:46:42

标签: python django django-models

我正在使用我的django app建立模型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类。
  2.     class BookmarkPlayer(Player):
            """ just a bookmark player"""
            class Meta:
                app_label = "core"
    
    1. 我可以将Player模型的所有字段定义为BookmarkPlayer模型。
    2.      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属性用于Abstract模型,我会得到答案。
      这通常会导致抽象基类出现问题,因为此类中的字段包含在每个子类中,每次都具有完全相同的属性值(包括related_name)。
      若要解决此问题,当您在抽象基类(仅)中使用related_name时,名称的一部分应包含'%(app_label)s'和'%(类)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
      

2 个答案:

答案 0 :(得分:9)

如果您的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是抽象的,因此模型完全解耦。

另一方面,多表继承仍然会将字段保存在单个表中,但是为BookmarkPlayer添加一个额外的表,并向OneToOneField表添加隐式Player

答案 1 :(得分:0)

这里有一些关于模型继承的好信息: https://docs.djangoproject.com/en/1.7/topics/db/models/#model-inheritance

选项2将引入重复,这总是很糟糕。如果BookmarkPlayer没有任何新字段,只有不同的方法,我建议您使用链接中描述的“代理模型”选项,因为您不需要BookmarkPlayer拥有自己的表数据库。

如果它需要它自己的表,“多表不干扰”是你要去的方式,这将是你问题中的选项1