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

Pra*_*aur 3 python django django-models

我正在Player使用我的django应用程序模型.

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)
Run Code Online (Sandbox Code Playgroud)

根据我的要求,我需要创建一个具有模型BookmarkPlayer所有领域的新Player模型.

现在我有两件事要做到这一点.

  1. 我可以为BookmarkPlayer模型扩展Player类.
    class BookmarkPlayer(Player):
        """ just a bookmark player"""
        class Meta:
            app_label = "core"
  1. 我可以将Player模型的所有字段定义为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属性用于Abstract模型,我会得到答案.
这通常会导致抽象基类出现问题,因为此类中的字段包含在每个子类中,每次都具有完全相同的属性值(包括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

knb*_*nbk 8

如果您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
Run Code Online (Sandbox Code Playgroud)

这样,从模型中继承PlayerBookmarkPlayer继承它们的字段BasePlayer,但由于它BasePlayer是抽象的,因此模型完全解耦.

另一方面,多表继承仍然会将字段保存在单个表中,但为表BookmarkPlayer隐式添加一个额外OneToOneFieldPlayer表.