使用Django MTI找出子类型或将类型指定为字段?

时间:2010-10-21 17:59:42

标签: python django django-models

我正在使用多表继承(MTI)在django中设置数据模型,如下所示:

class Metric(models.Model):
    account = models.ForeignKey(Account)
    date = models.DateField()
    value = models.FloatField()
    calculation_in_progress = models.BooleanField()
    type = models.CharField( max_length=20, choices= METRIC_TYPES ) # Appropriate?

    def calculate(self):
        # default calculation...

class WebMetric(Metric):
    url = models.URLField()

    def calculate(self):
        # web-specific calculation...

class TextMetric(Metric):
    text = models.TextField()

    def calculate(self):
        # text-specific calculation...

我的直觉是在基类中放置一个'type'字段,如下所示,所以我可以告诉任何Metric对象属于哪个子类。一直保持最新状态会有点麻烦,但可能。但我需要这样做吗? django有什么方法可以自动处理这个问题吗?

当我调用Metric.objects.all()时,返回的每个对象都是Metric的实例,而不是子类。所以,如果我打电话给.calculate(),我永远不会得到子类的行为。

我可以在基类上编写一个函数来测试是否可以将它转换为任何子类型,如:

def determine_subtype(self):
    try:
        self.webmetric
        return WebMetric
    except WebMetric.DoesNotExist:
        pass
    # Repeat for every sub-class

但这似乎是一堆重复的代码。它也不是可以包含在SELECT过滤器中的东西 - 只适用于python-space。

处理此问题的最佳方法是什么?

2 个答案:

答案 0 :(得分:1)

虽然它可能会冒犯一些人的敏感性,但解决这个问题的唯一可行方法是在基类中放置一个字段或一个方法,它说明每个记录实际上是什么类型的对象。您描述的方法的问题是,对于您正在处理的每个对象,它需要为每种类型的子类分别进行数据库查询。使用大型查询集时,这可能会非常慢。更好的方法是将ForeignKey用于django Content Type类。

@Carl Meyer在这里写了一个很好的解决方案:How do I access the child classes of an object in django without knowing the name of the child class?

单表继承可以帮助缓解此问题,具体取决于它的实现方式。但是现在Django不支持它:Single Table Inheritance in Django所以这不是一个有用的建议。

答案 1 :(得分:-1)

  

但我需要这样做吗?

从不。决不。从不。

  

django有什么方法可以自动处理这个问题吗?

是。它被称为“多态”。

从不需要知道子类。从不。

“我的WebMetric.url和TextMetric.text属性怎么样?”

您对这些属性做什么?定义某事的方法函数。在WebMetric(使用url)和TextMetric(使用文本)中实现不同的版本。 这是正确的多态性。


请阅读:http://docs.djangoproject.com/en/1.2/topics/db/models/#abstract-base-classes

请将您的超类抽象化。

请勿这样做:http://docs.djangoproject.com/en/1.2/topics/db/models/#multi-table-inheritance

您想要“单表继承”。