在 django 中获取继承的模型对象
Posted
技术标签:
【中文标题】在 django 中获取继承的模型对象【英文标题】:Fetching inherited model objects in django 【发布时间】:2011-07-07 16:42:34 【问题描述】:我有一个具有以下模型的 django 应用程序:
Object A 是一个从 Model 扩展而来的简单对象,有几个字段,比方说,一个特定的对象是一个名为 "NAME" 的 char 字段和一个 Integer 字段称为“订单”。 A 是抽象的,表示数据库中没有 A 对象,而是...
对象 B 和 C 是 A 的特化,这意味着它们继承自 A 并添加了其他一些字段。
现在假设我需要字段 NAME 以字母 "Z" 开头的所有对象,按 ORDER 字段排序,但我也希望这些对象的所有 B 和 C 特定字段。现在我看到了两种方法:
a) 分别对 B 和 C 对象进行查询,并获取两个列表,合并它们,手动排序并使用它。
b) 查询 A 对象以查找以 "Z" 开头并按 "ORDER" 排序的名称,结果查询 B 和 C 对象带来所有剩余的数据。
这两种方法听起来效率很低,第一种方法我必须自己订购,第二种方法我必须多次查询数据库。
我是否缺少一种神奇的方式来获取所有 B 和 C 对象,以一种方法排序?或者至少比上述两种方法更有效?
提前致谢!
布鲁诺
【问题讨论】:
欢迎使用 Django 模型继承。享受(!)您的住宿。 【参考方案1】:如果A
可以是具体的,您可以使用select_related
在一个查询中完成所有操作。
from django.db import connection
q = A.objects.filter(NAME__istartswith='z').order_by('ORDER').select_related('b', 'c')
for obj in q:
obj = obj.b or obj.c or obj
print repr(obj), obj.__dict__ # (to prove the subclass-specific attributes exist)
print "query count:", len(connection.queries)
【讨论】:
聪明。可怕,但很聪明。但是,当 A 是抽象的时不起作用? 正确的,仅限具体的多表继承。 我同意 Wogan 的观点,从概念上讲它很丑陋,但它就像一个魅力,只要我们可以制作 A 混凝土,这对我来说并不是一件可怕的事情!非常聪明!【参考方案2】:此问题已回答here。
使用来自django-model-utils 项目的InheritanceManager。
【讨论】:
【参考方案3】:使用您的“b”方法进行查询,将允许您“引入”所有剩余数据,而无需分别查询您的 B 和 C 模型。您可以使用“点小写模型名称”关系。
http://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance
for object in A.objects.filter(NAME__istartswith='z').order_by('ORDER'):
if object.b:
// do something
pass
elif object.c:
// do something
pass
您可能需要尝试排除 DoesNotExist 异常。我对我的 django 有点生疏了。祝你好运。
【讨论】:
是的,您需要捕获DoesNotExist
,并且每次访问相关对象的尝试(成功与否)都会花费您额外的查询——效率极低。【参考方案4】:
只要您对 B 和 C 的两个查询都排序,就可以很容易地合并它们,而无需采取昂贵的手段:
# first define a couple of helper functions
def next_or(iterable, other):
try:
return iterable.next(), None
except StopIteration:
return None, other
def merge(x,y,func=lambda a,b: a<=b):
''' merges a pair of sorted iterables '''
xs = iter(x)
ys = iter(y)
a,r = next_or(xs,ys)
b,r = next_or(ys,xs)
while r is None:
if func(a,b):
yield a
a,r = next_or(xs,ys)
else:
yield b
b,r = next_or(ys,xs)
else:
if a is not None:
yield a
else:
yield b
for o in r:
yield o
# now get your objects & then merge them
b_qs = B.objects.filter(NAME__startswith='Z').order_by('ORDER')
c_qs = C.objects.filter(NAME__startswith='Z').order_by('ORDER')
for obj in merge(b_qs,c_qs,lambda a,b: a.ORDER <= b.ORDER):
print repr(obj), obj.__dict__
这种技术的优点是它适用于抽象基类。
【讨论】:
以上是关于在 django 中获取继承的模型对象的主要内容,如果未能解决你的问题,请参考以下文章