Django ORM,按类型过滤对象并使用模型继承

时间:2009-09-19 04:30:04

标签: python django django-models

所以我有两个模特......

父母与子女。

Child扩展Parent。

当我这样做时

Parent.objects.all(),我得到了父母和孩子。

我只想要父母

我是否可以使用Parent.objects.filter()参数来获取父对象而不是扩展父对象的对象?

4 个答案:

答案 0 :(得分:13)

我找到了一种更好的方法来解决这个问题,使用django ORM并且无需对模型进行任何更改(例如ABC):

class Parent(models.Model):
    field1 = models.IntegerField()
    field2 = models.IntegerField()

class Child(Parent):
    field3 = models.IntegerField()

#Return all Parent objects that aren't also Child objects:
Parent.objects.filter(child=None)

这将导致以下查询(概念,实际查询可能会有所不同):

  

SELECT“ap_parent”。“field1”,“ap_parent”。“field2”FROM“ap_parent”INNER   加入“ap_child”ON   (“parent”。“parent_ptr_id”=   “ap_child”。“parent_ptr_id”)WHERE   “ap_child”。“parent_ptr_id”IS NULL

答案 1 :(得分:3)

也许这是一个使用 A bstract B ase C lass而不是使用继承的好地方。 ABC保存您班级中常见的所有字段。因此,在您的情况下,您将拥有一个主要定义的ABC具有您当前的父类和2个将继承自ABC的类,这些类对应于您的父类和子类。

class ABC(models.Model):
    field1 = models.CharField(max_length=200)
    field2 = models.CharField(max_length=100)
    ....

    class Meta:
        abstract = True

class Parent(ABC):
    ....

class Child(ABC):
    parent = models.ForeignKey(Parent)

点击此处了解详情:Model inheritance and Abstract base classes

答案 2 :(得分:2)

您确定继承是正确的解决方案吗?那怎么样?

class MyModel(models.Model):
    foo = models.IntegerField()
    parent = models.ForeignKey("self", null=True)

然后你可以查询像这样的父类的所有对象:

parents = MyModel.objects.filter(parent__isnull=True)
children = MyModel.objects.filter(parent__isnull=False)

@Alex:根据类型进行过滤将无法正常工作。 Django的继承模型并不是那么丰富。例如。使用这些模型:

class Parent(models.Model):
    foo = models.CharField(max_length=5)

class Child(Parent):
    bar = models.CharField(max_length=5)

你得到这种行为:

In [1]: from myexample.models import Parent, Child

In [2]: p = Parent(foo='x')

In [3]: p.save()

In [4]: p2 = Parent(foo='y')

In [5]: p2.save()

In [6]: c1 = Child(bar='1', foo='a')

In [7]: c1.save()

In [8]: c2 = Child(bar='2', foo='b')

In [9]: c2.save()

In [10]: len(Parent.objects.all())
Out[10]: 4

In [11]: len([p for p in Parent.objects.all() if type(p) is Parent])
Out[11]: 4

In [12]: len(Child.objects.all())
Out[12]: 2

答案 3 :(得分:1)

filter方法本质上是关于在SQL查询中构建WHERE子句,这是一个非常难以解决的确切类型的地方。那么,而不是......:

(p for Parent.objects.all() if type(p) is Parent)

这是一个可迭代的(在外部使用[ ]而不是( ),如果你想要一个列表,而不是所有完全类型为Parent的对象 - 没有子类允许的。