更好的替代方法,而不是在Django ORM中使用链式联合查询

时间:2018-10-13 17:16:14

标签: python django orm django-orm paginator

我需要在Django ORM中实现以下目标:

(SELECT * FROM `stats` WHERE MODE = 1 ORDER BY DATE DESC LIMIT 2) 
UNION
(SELECT * FROM `stats` WHERE MODE = 2 ORDER BY DATE DESC LIMIT 2)     
UNION                                                                       
(SELECT * FROM `stats` WHERE MODE = 3 ORDER BY DATE DESC LIMIT 2)
UNION                                                                         
(SELECT * FROM `stats` WHERE MODE = 6 ORDER BY DATE DESC LIMIT 2) 
UNION
(SELECT * FROM `stats` WHERE MODE = 5 AND is_completed != 3 ORDER BY DATE DESC)                                                                           
# mode 5 can return more than 100 records so NO LIMIT here 

我为此写的:

query_run_now_job_ids = Stats.objects.filter(mode=5).exclude(is_completed=3).order_by('-date')
list_of_active_job_ids = Stats.objects.filter(mode=1).order_by('-date')[:2].union(
                            Stats.objects.filter(mode=2).order_by('-date')[:2],
                            Stats.objects.filter(mode=3).order_by('-date')[:2],
                            Stats.objects.filter(mode=6).order_by('-date')[:2],
                            query_run_now_job_ids)

但是以某种方式返回的 list_of_active_job_ids 是无序的,即list_of_active_job_ids.ordered返回 False ,由于此查询传递给 Paginator 类时,给出:

UnorderedObjectListWarning: 
Pagination may yield inconsistent results with an unordered object_list  

我已经在models.py中的Meta类中设置了排序

class Meta:
        ordering = ['-date']

没有分页器查询可以很好地工作并且可以加载页面,但是使用分页器时,视图永远不会加载。

在不使用联合链的情况下,还有其他更好的替代方案吗?

因此,我尝试了上述MySQL查询的另一种替代方法,但在此查询中,我陷入了另一个问题,无法为 mode = 5 编写条件:

SELECT  
    MODE ,
    SUBSTRING_INDEX(GROUP_CONCAT( `job_id` SEPARATOR ',' ),',',2) AS job_id_list,
    SUBSTRING_INDEX(GROUP_CONCAT( `total_calculations` SEPARATOR ',' ),',',2) AS total_calculations
FROM `stats`            
ORDER BY DATE DESC 

即使我能够编写此查询,它也将导致我进入另一个具有挑战性的情况,即将该查询转换为Django ORM。

那么,即使我在Class Meta中进行了设置,为什么我的查询也没有排序。

如果不是此查询,是否还有更好的替代方法实现?

我们将不胜感激!

我正在使用Python 2.7和Django 1.11。

1 个答案:

答案 0 :(得分:0)

虽然可以查询子查询,但不能查询结果联合数据。您需要明确定义顺序。

from django.db import models

def make_query(mode, index):
    return (
        Stats.objects.filter(mode=mode).
        annotate(_sort=models.Value(index, models.IntegerField())).
        order_by('-date')
    )

list_of_active_job_ids = make_query(1, 1)[:2].union(
     make_query(2, 2)[:2],
     make_query(3, 3)[:2],
     make_query(6, 4)[:2],
     make_query(5, 5).exclude(is_completed=3)
).order_by('_sort', '-date')

我要做的就是添加一个新的文字值字段_sort,该字段的每个子查询都有不同的值,然后在最终查询中对其进行排序。其余代码只是为了减少重复。如果不是那个mode=6子查询,它甚至会更干净。