Skip to main content
 首页 » 编程设计

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

2025年05月04日31thcjp

我正在使用多表继承 (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... 

我的直觉是在基类中放置一个“类型”字段,如此处所示,这样我就可以分辨出任何 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 空间。

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

请您参考如下方法:

虽然它可能会冒犯某些人的敏感度,但解决此问题的唯一实用方法是在基类中放置一个字段或一个方法,说明每条记录到底是什么类型的对象。您描述的方法的问题在于,对于您正在处理的每个对象,它需要对每种类型的子类进行单独的数据库查询。在处理大型查询集时,这可能会变得非常慢。更好的方法是对 django 内容类型类使用 ForeignKey。

@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所以这不是一个有用的建议。