在 django 中获取继承的模型对象

Posted

技术标签:

【中文标题】在 django 中获取继承的模型对象【英文标题】:Fetching inherited model objects in django 【发布时间】:2011-07-07 16:42:34 【问题描述】:

我有一个具有以下模型的 django 应用程序:

Object A 是一个从 Model 扩展而来的简单对象,有几个字段,比方说,一个特定的对象是一个名为 "NAME" 的 char 字段和一个 Integer 字段称为“订单”A 是抽象的,表示数据库中没有 A 对象,而是...

对象 BCA 的特化,这意味着它们继承自 A 并添加了其他一些字段。

现在假设我需要字段 NAME 以字母 "Z" 开头的所有对象,按 ORDER 字段排序,但我也希望这些对象的所有 BC 特定字段。现在我看到了两种方法:

a) 分别对 BC 对象进行查询,并获取两个列表,合并它们,手动排序并使用它。

b) 查询 A 对象以查找以 "Z" 开头并按 "ORDER" 排序的名称,结果查询 BC 对象带来所有剩余的数据。

这两种方法听起来效率很低,第一种方法我必须自己订购,第二种方法我必须多次查询数据库。

我是否缺少一种神奇的方式来获取所有 BC 对象,以一种方法排序?或者至少比上述两种方法更有效?

提前致谢!

布鲁诺

【问题讨论】:

欢迎使用 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 中获取继承的模型对象的主要内容,如果未能解决你的问题,请参考以下文章

在 Django 中获取模型表单的保存对象?

Django:获取模型字段列表?

Django:在ManyToManyField中获取属于模型对象的第一个项目

Django使用“通过”关系表从模型中获取所有相关对象

获取所有相关的 Django 模型对象

如何获取模型的名称或 Django 对象的内容类型?