12

在我的具体情况下,我有两种需要检索和分页的“消息”。

我们省略细节,只说第一种在名为Msg1的模型中,另一种称为Msg2

这两个模型的字段是完全不同的,两个模型共同的唯一字段是“日期”和“标题”(当然还有id)。

我可以得到Msg1.objects.all()Msg2.objects.all()但我可以将这两个查询组合成一个查询,按日期排序,然后分页吗?

我需要保留查询的惰性。

简单的解决方案是list(query)同时查询并将它们组合在 python 列表中。但由于显而易见的原因,这是低效的。

我查看了模型和 dp-api 上的 django 引用,但似乎没有一种方法可以将不同模型/表的查询组合成一个。

4

2 回答 2

11

我建议您使用模型继承

创建一个包含日期和标题的基础模型。如所述,子类 Msg1 和 Msg2 关闭它。使用基本模型执行所有查询(以填充页面),然后在最后一刻切换到派生类型。

继承的真正好处是 django 允许您在其他模型的外键中使用基本模型,因此您可以使整个应用程序更加灵活。在引擎盖下,它只是基本模型的一个表,每个子模型包含一个包含一对一键的表。

于 2008-11-24T00:35:42.353 回答
2

“将这两个查询合并为一个查询,按日期排序,并分页?”

  1. 这就是 SQL 联合。离开 Django ORM 并使用 SQL 联合。它的速度并不快,因为 SQL 必须创建一个临时结果,并对其进行排序。

  2. 创建可以排序的临时结果。由于列表具有排序方法,因此您必须将两个结果合并到一个列表中。

  3. 编写一个接受两个查询集的合并算法,对结果进行分页。


编辑。这是一个合并算法。

def merge( qs1, qs2 ):
    iqs1= iter(qs1)
    iqs2= iter(qs2)
    k1= iqs1.next()
    k2= iqs2.next()
    k1_data, k2_data = True, True
    while k1_data or k2_data:
        if not k2_data:
            yield k1
            try:
                k1= iqs1.next()
            except StopIteration:
                k1_data= False
        elif not k1_data:
            yield k2
            try:
                k2= iqs2.next()
            except StopIteration:
                k2_data= False
        elif k1.key <= k2.key:
            yield k1
            try:
                k1= iqs1.next()
            except StopIteration:
                k1_data= False
        elif k2.key < k1.key: # or define __cmp__.
            yield k2
            try:
                k2= iqs2.next()
            except StopIteration:
                k2_data= False
        else:
            raise Exception( "Wow..." )

您可以折叠分页:

def paginate( qs1, qs2, start=0, size=20 ):
    count= 0
    for row in merge( qs1, qs2 ):
        if start <= count < start+size:
            yield row
        count += 1
        if count == start+size:
            break
于 2008-11-24T00:10:39.423 回答