如何根据字段的值来增加额外的django模型字段?

时间:2017-01-21 19:06:21

标签: python django django-models

我的Django项目中有一个名为Job的模型。每个工作都有一个类别。类别的示例可以是辅导。这可以表示为我的模型现在的样子:

from __future__ import unicode_literals

from django.db import models

class Job(models.Model):

    # Abbreviations for possible categories to be stored in the database.
    TUTORING = "TU"
    PETSITTING = "PS"
    BABYSITTING = "BS"
    INTERIOR_DESIGN = "IND"
    SHOPPING = "SH"
    SOFTWARE_DEVELOPMENT = "SD"
    DESIGN = "DE"
    ART = "AR"
    HOUSEKEEPING = "HK"
    OTHER = "OT"

    JOB_CATEGORY_CHOICES = (
        (TUTORING, 'Tutoring'),
        (PETSITTING, "Petsitting"),
        (BABYSITTING, "Babysitting"),
        (INTERIOR_DESIGN, "Interior Design"),
        (SHOPPING, "Shopping"),
        (SOFTWARE_DEVELOPMENT, "Software Development"),
        (DESIGN), "Design"),
        (ART, "Art"),
        (HOUSEKEEPING, "Housekeeping"),
        (OTHER, "Other"),
    )

    created_at = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=255)
    description = models.TextField()
    category = models.CharField(max_length=3, choices=JOB_CATEGORY_CHOICES, default=OTHER,)

    def __str__(self):
        return self.title

根据作业的类别,需要不同的字段。例如,如果我再次将辅导作为类别,则需要额外的字段,例如addresssubject,学习级别和其他字段。如果Job的类别是软件开发,则需要project_sizerequired_qualifications等额外字段。

我是否应该为每种类型的Job创建一个单独的模型,或者是否存在某种模型继承,我可以使用其中作业类型从主Job模型继承,其中包含所有Jobs所需的所有公共字段。

基本上,根据作业类别有多余字段的最佳方法是什么?

2 个答案:

答案 0 :(得分:1)

你有一些选择:

1。关于各种类别模型的OneToOneField

  • 临: 允许其他模型将FK设置为​​Job模型。例如。无论哪个类别,您都可以通过person.jobs.all()检索所有人的工作。

  • 缺点: 允许不同类别的实例与同一个Job实例相关:需要额外的工作来维护数据完整性

    更多表格,更多联接,更慢的查询

    添加类别总是需要迁移!

2。 Multi-Table继承:

在引擎盖下使用OneToOneField

  • 临: 如上所述+但是类别的每个实例都会自动创建自己的Job实例,因此类别之间不会发生冲突。

  • 缺点: 更多表,更多联接,更慢的查询。隐藏了一些正在发生的数据库内容。

    添加类别总是需要迁移!

3。 Job作为抽象基础模型

  • Pro:每个类别的单个表格,更快的查询

  • Con:需要为每个类别保持单独的关系,不能在db级别进行分组。

    添加类别总是需要迁移!

4。将所有类别特定字段放在Job中(并使其可为空)

  • Pro:一个表,简单的关系,通过category字段上的过滤器查询特殊类别仍然可行。

    您可以使用特定的模型管理器来处理类别:Job.tutoring.all()

    可能有很多类别共享不同的字段子集

    没有过度工程,易于维护。

    如果需要一个尚未存在的字段,添加新类别只需要迁移。您可以使用多个类别使用的通用CharField用于不同的语义目的,并通过propertys使用有意义的名称访问它。但是,这些不能用于过滤器或qs更新。

Àla:

class Job(models.Model):
    # ...
    attribute = models.CharField(...)

    def _get_attribute(self):
        return self.attribute

    def _set_attribute(self, value):
        self.attribute = value

    # for shopping
    shop_name = property(_get_attribute, _set_attribute)

    # for babysitting
    family_name = property(_get_attribute, _set_attribute)

# then you can use
babysitting_job.family_name = 'Miller'
  • Con:每个作业的某些字段为空

虽然选项1-3可以更好地模拟现实世界并让您对已经熟练的复杂模型结构感觉良好,但我不会太快地丢弃选项4。

如果类别字段很少并且通常在类别之间共享,那么这将是我的方法。

答案 1 :(得分:0)

最好的办法是使用OneToOneField。在进一步解释之前,我将使用这个例子:

    from django.db import models

    class Menu(models.Model):
        name = models.CharField(max_length=30)


    class Item(models.Model):
        menu = models.OneToOneField(Menu)
        name = models.CharField(max_length=30)
        description = models.CharField(max_length=100)

这里的菜单可以与您的工作模型进行比较。选择菜单中的项目后,菜单模型基本上会扩展所选项目的字段。此处的项目可与您的工作类别进行比较。

您可以阅读有关此内容的更多信息here