Django ORM的奇怪行为

时间:2014-08-04 13:36:05

标签: python mysql django orm django-queryset

我正在使用Django ORM来执行一个看起来像这样的复杂查询:

user_ids = MyLog.objects.values('user_id').annotate(
    last_configured=Max('configured')
).exclude(
    last_configured__lt=earlier_date
).filter(content_type_id=configuration_content_type).values_list('user_id', flat=True)

评估为:

SELECT `customer_mylog`.`user_id`, MAX(`customer_mylog`.`configured`)
AS `last_configured` FROM `customer_mylog`
WHERE (`customer_mylog`.`content_type_id` = 654 )
GROUP BY `customer_mylog`.`user_id`
HAVING NOT (MAX(`customer_mylog`.`configured`) < 2014-04-19 20:22:38.729416 )
ORDER BY NULL

此时,我确信查询尚未执行,除非我执行len(user_ids)之类的操作,但我不这样做。然后我通过这样做来修改它:

new_user_ids = User.objects.filter(pk__in=user_ids).exclude(date_joined__lt=earlier_date).exists()

将原始查询更改为:

SELECT `auth_user`.`id`, `auth_user`.`username`, `auth_user`.`first_name`, `auth_user`.`la 
st_name`, `auth_user`.`email`, `auth_user`.`password`, `auth_user`.`is_staff`, `auth_user`.` 
is_active`, `auth_user`.`is_superuser`, `auth_user`.`last_login`, `auth_user`.`date_joined`  
FROM `auth_user` WHERE (`auth_user`.`id` IN (SELECT U0.`user_id` FROM `customer_mylo 
g` U0 WHERE (U0.`content_type_id` = 654 ) GROUP BY U0.`user_id` HAVING NOT (MAX(U0.`configured`)  
< 2014-05-04 13:04:48.204187 ) ORDER BY NULL) AND NOT (`auth_user`.`date_joined` < 2014-05-0 
4 13:04:48 ))

如果我通过执行list(new_user_ids)之类的操作来执行查询,它永远不会完成执行。它既没有失败,也没有给出任何错误信息。

所以相反,我尝试了以下方法,它以某种方式完美地工作。

for user_id in user_ids:
    if User.objects.filter(pk=user_id).exclude(date_joined__lt=earlier_date).exists():
        new_user_ids.append(user_id)

为什么以前的方法不起作用,尽管两者在他们试图做的事情上都有相似之处?

2 个答案:

答案 0 :(得分:2)

不直接评估Django Querysets,以便让ORM评估它们并查询您需要对它们执行实际操作所需的基础数据库:

https://docs.djangoproject.com/en/1.6/ref/models/querysets/#when-querysets-are-evaluated

答案 1 :(得分:0)

不同之处在于,您在一个查询集上调用.exists(),在数据库中执行所有繁重的操作并获取布尔值,而另一个是filter并将所有内容加载到在Python对象上内存已满。

你的最后一段代码,exists()检查实际上并没有实例化任何对象,它只检查数据库是否与用户匹配查询并停止,而不是生成所有用户的列表对象

需要更多的时间来实例化所有模型而不仅仅是计算它是否可以实例化它们。