代码之家  ›  专栏  ›  技术社区  ›  T. Stone

django可以执行嵌套查询和排除吗

  •  1
  • T. Stone  · 技术社区  · 14 年前

    我需要一些帮助把这个问题放在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中的用户的数据一次显示为真,因此这将排除记录4。

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

    如何使用django orm进行此查询?

    3 回复  |  直到 14 年前
        1
  •  5
  •   Oli    14 年前

    不需要嵌套查询。您可以生成坏用户的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个完整的查询)实际上可以更快地运行。

    两个都试试,和他们比赛!

        2
  •  0
  •   Vasiliy Stavenko    14 年前

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

    F 版本中的可用对象 1.0

    请测试一下,我不确定。

        3
  •  0
  •   istruble kalyan    14 年前

    由于懒惰的计算,您可以将查询分解为几个不同的变量,使其更易于阅读。这里有一些 ./manage.py shell 以奥利已经展示过的风格打球。

    > 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() 如果要在同一查询中拉入用户对象。