2011-03-02 69 views
8

我有以下的模型Django应用程序:抓取继承的模型对象

对象一个是有几个字段从模型延伸的简单对象,让我们说,一个特定的一个是char场称为“名称”和整数字段称为“订单”一个是抽象的,这意味着没有一个对象在数据库中,而是......

对象ç一个专业化,这意味着他们从一继承他们添加了一些其他领域。

现在假设我需要它的领域NAME的所有对象以字母开始“Z”,由ORDER字段排序,但我想所有的ç特异的领域太为那些对象。现在,我看到2种方法:

一)执行查询单独为ç对象和手动取两份名单,将它们合并,以便与这项工作。

b)中查询对象用于开始与“Z”“ORDER”,并用结果查询Ç对象命令将所有剩余的数据名称。

这两种方法听起来效率非常低,在第一个我必须自己命令他们,在第二个我必须多次查询数据库。

有我缺少获取所有Ç目的,在一个单一的方法下令神奇的方式?或者至少比这两个提到的更有效的方法呢?

在此先感谢!

布鲁诺

+1

欢迎来到Django模型继承。入住愉快。 – 2011-03-03 02:31:32

回答

5

如果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) 
+0

聪明。可怕,但聪明。当A是抽象的时候不会工作吗? – Wogan 2011-03-03 07:39:33

+0

只有正确,具体的多表继承。 – DrMeers 2011-03-03 07:41:11

+0

啊,我在第一次阅读时设法跳过了“A是抽象的”一词... – DrMeers 2011-03-03 09:25:50

0

使用“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有点生疏。祝你好运。

+0

是的,您需要捕获'DoesNotExist',并且每个尝试访问相关对象(成功与否)都会花费您额外的查询 - 效率非常低。 – DrMeers 2011-03-03 07:03:46

0

只要您订购的两个查询在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__ 

这种技术的优点是它的工作原理与抽象基类。