如何在两个不同的相关字段上进行过滤,并在一个查询中满足它们?

时间:2016-12-20 20:05:00

标签: django django-models

我有一些模型的关系如下:

class Container(models.Model):
    pass

class Child(models.Model):
    container = models.ForeignKey(Container, related_name='children')
    tag = models.CharField(max_length=40)
    val = models.IntegerField()

我想过滤容器是否可以找到两个单独的 children,其中一个tag 'foo'val } [1,2,3] 另一个tag bar val [3,4,5]。{/ p>

当我按以下方式过滤时:

print list(Container.filter( 
  Q(children__tag='foo', val__in=[1,2,3]) & 
  Q(children__tag='bar', val__in=[5,6,7]))
).distinct()

Django太聪明了。它会对每个Child进行过滤,以确保它具有 tag 'foo''bar'以及中的值 [1,2,3][5,6,7],其中包含以下SQL:

SELECT 
    COUNT(DISTINCT `app_container`.`id`)
FROM
    `app_container`
        INNER JOIN
    `app_child` ON (`app_container`.`id` = `app_child`.`container_id`)
WHERE
  app_child.tag = 'foo' 
  AND app_child.val in (1,2,3)
  AND app_child.tag = 'bar' 
  AND app_child.val in (5,6,7)

我希望django做以下的事情来获得Container与两个不同的孩子:

SELECT 
    COUNT(DISTINCT `app_container`.`id`)
FROM
    `app_container`
        LEFT JOIN
    `app_child` c1 ON (`app_container`.`id` = `c1`.`container_id`)
        LEFT JOIN
    `app_child` c2 ON (`app_container`.`id` = `c1`.`container_id`)
WHERE
  c1.tag = 'foo' 
  AND c1.val in (1,2,3)
  AND c2.tag = 'bar' 
  AND c2.val in (5,6,7)

2 个答案:

答案 0 :(得分:2)

如果内存服务,一种方法是链接过滤器调用:

 Container.objects() \
    .filter(children__tag='foo', children__val__in=[1,2,3]) \
    .filter(children__tag='bar', children__val__in=[5,6,7]) \
    .distinct()

一对多的filter查找符合条件的单个相关对象,但两个链接的调用应该彼此独立。

答案 1 :(得分:0)

我提出了一个解决方案,但我不确定其他人是否更有效率:

print list(Container.filter(
  Q(pk__in=Container.objects.filter(children__tag='foo', val__in=[1,2,3])) &
  Q(pk__in=Container.objects.filter(children__tag='bar', val__in=[4,5,6]))
).distinct()