Django ORM, 通过模型继承按类型过滤对象
我有两个模型……
一个是父类(Parent),一个是子类(Child)。
子类是从父类扩展出来的。
当我执行
Parent.objects.all()时,我得到了父类和子类的所有对象。
但我只想要父类的对象。
有没有什么方法,比如使用 Parent.objects.filter(),可以让我只获取父类的对象,而不包括那些扩展自父类的对象呢?
4 个回答
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
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 JOIN "ap_child" ON ("parent"."parent_ptr_id" = "ap_child"."parent_ptr_id") WHERE "ap_child"."parent_ptr_id" IS NULL
4
也许在这里使用一个抽象基类会比直接用继承更好。这个抽象基类包含了你所有类中共有的字段。所以在你的情况下,你可以创建一个抽象基类,它的定义大致和你现在的父类相同,然后再有两个类从这个抽象基类继承,这两个类分别对应你的父类和子类。
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)
想了解更多信息,可以查看这里:模型继承和抽象基类