python - 创建一个新模型,其中包含当前现有模型的所有字段

标签 python django django-models

我的 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"
  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 属性,我终于得到了答案。
这通常会在抽象基类中引起问题,因为此类中的字段包含在每个子类中,每次都具有完全相同的属性值(包括 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

最佳答案

如果您的 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 表。

关于python - 创建一个新模型,其中包含当前现有模型的所有字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27272138/

相关文章:

python - 将tensorflow/keras模型转换为tensorflow lite模型时出现问题

python - 如何使用 OpenNI 绑定(bind)在 OpenCV 中打印 Kinect 帧

python - 从脚本填充数据库时出现 Django Heroku DataError

python - 如何在 django 表单的查询集上使用切片?

python - 使用 Python 子进程执行 tar 命令在给定 --exclude 选项时不会排除某些文件

python - virtualenv 中的 IPython Notebook,使用 Python 3.3

python - Django数据库规划-时序数据

javascript - 每分钟更新一次高排行榜?

django-models - Django 查询基于更大的日期

python - Django在外键字段中添加下划线,有没有办法删除它?