4

我需要一些帮助将这个查询放在 Django 中。我已经简化了这里的示例,以切入正题。

MyModel(models.Model):
    created = models.DateTimeField()
    user = models.ForeignKey(User)
    data = models.BooleanField()

我想用英语创建的查询听起来像:

给我昨天创建的每条数据为假的记录,在同一范围内,给定用户的数据永远不会显示为真

这是一个示例输入/输出,以防不清楚。

表值

ID   Created    User    Data

1    1/1/2010   admin   False
2    1/1/2010   joe     True
3    1/1/2010   admin   False
4    1/1/2010   joe     False
5    1/2/2010   joe     False

输出查询集

1    1/1/2010   admin   False
3    1/1/2010   admin   False

我要做的是排除记录#4。这样做的原因是因为在“昨天”的给定范围内,记录 #2 中的用户的数据显示为 True 一次,因此将排除记录 #4。

从某种意义上说,似乎发生了 2 个查询。一种用于确定给定范围内的记录,另一种用于排除与“真”记录相交的记录。

如何使用 Django ORM 进行此查询?

4

3 回答 3

6

您不需要嵌套查询。您可以生成不良用户的 PK 列表,然后在下一个查询中排除包含这些 PK 的记录。

bad = list(set(MyModel.obejcts.filter(data=True).values_list('user', flat=True)))
# list(set(list_object)) will remove duplicates
# not needed but might save the DB some work

rs = MyModel.objects.filter(datequery).exclude(user__pk__in=bad)
# might not need the pk in user__pk__in - try it

您可以将其浓缩为一行,但我认为这与您将得到的一样整洁。2个查询还不错。

编辑:您可能想阅读有关此的文档:

http://docs.djangoproject.com/en/dev/ref/models/querysets/#in

如果是这样的话,它听起来像是自动嵌套查询(因此只有一个查询在数据库中触发):

bad = MyModel.objects.filter(data=True).values('pk')
rs  = MyModel.objects.filter(datequery).exclude(user__pk__in=bad)

但是MySQL 并没有很好地优化这一点,所以我上面的代码(2 个完整查询)实际上最终可以运行得更快。

尝试两者并与它们比赛!

于 2010-03-01T22:55:53.790 回答
0

看起来你可以使用: from django.db.models import F MyModel.objects.filter(datequery).filter(data=False).filter(data = F('data'))

F版本中可用的对象1.0

请测试一下,我不确定。

于 2010-03-01T23:25:45.880 回答
0

由于惰性评估,您可以将查询分解为几个不同的变量,以使其更易于阅读。./manage.py shell这是Oli 已经呈现的风格的一些游戏时间。

> from django.db import connection
> connection.queries = []
> target_day_qs = MyModel.objects.filter(created='2010-1-1')
> bad_users = target_day_qs.filter(data=True).values('user')
> result = target_day_qs.exclude(user__in=bad_users)
> [r.id for r in result]
[1, 3]
> len(connection.queries)
1

你也可以说result.select_related()你是否想在同一个查询中拉入用户对象。

于 2010-03-01T23:56:40.963 回答