创建表示查询集联合的查询集

时间:2013-01-09 04:16:21

标签: python django django-orm

假设我有以下型号:

class House(models.Model):
    address = models.CharField(max_length=255)

class Person(models.Model):
    name = models.CharField(max_length=50)
    home = models.ForeignKey(House, null=True, related_name='tenants')

class Car(models.Model):
    make = models.CharField(max_length=50)
    owner = models.ForeignKey(Person)

让我说我有需要(奇怪的,虽然)得到:

  • 住在一所房子里或被命名为'John'的人员名单
  • 上述人员的汽车列表

我想有两个功能:

  • get_tenants_or_johns(house)
  • get_cars_of_tenants_or_johns(house)

我可以将它们定义为:

from django.db.models.query_utils import Q

def get_cars_of_tenants_or_johns(house):
    is_john = Q(owner__in=Person.objects.filter(name='John'))
    is_tenant = Q(owner__in=house.tenants.all())
    return Car.filter(is_john | is_tenant)

def get_tenants_or_johns(house):
    johns = Person.objects.filter(name='John')
    tenants = house.tenants.all()
    return set(johns) | set(tenants)

问题是在上面的例子中重复了逻辑。如果我可以get_tenants_or_johns(house)返回queryset我可以将get_cars_of_tenants_or_johns(house)定义为:

def get_cars_of_tenants_or_johns(house):
    return Car.objects.filter(owner__in=get_tenants_or_johns(house))

为了做到这一点,get_tenants_or_johns(house)需要返回查询集的并集,而不将它们转换为其他集合。

我无法弄清楚如何实现get_tenants_or_johns(house),以便返回包含SQL UNION的查询集。有没有办法做到这一点?如果没有,是否有另一种方法来实现我想要做的事情?

2 个答案:

答案 0 :(得分:3)

两个查询集上的|运算符将返回表示联合的新查询集。

该函数需要更改为(摆脱set()包装器):

def get_tenants_or_johns(house):
    johns = Person.objects.filter(name='John')
    tenants = house.tenants.all()
    return johns | tenants

并且一切都将按照需要完成。

答案 1 :(得分:0)

您提到住在房子里的用户,但没有提及您的用户模型。

我认为你真的需要仔细研究你的应用程序的结构 - 可能有更简单的方法来实现你的目标。

但是要回答你的问题,让我们设置三个辅助函数。因为,正如我上面提到的,你没有概述你想用User类做什么 - 我假设将传递给这些函数的house是一个地址:

helpers.py

def get_johns(house):
    is_john = Person.objects.filter(name='John')
    return is_john

def get_cars_of_tenants(house):
    cars = Car.objects.filter(owner__home__address=house)
    return cars

def get_tenants(house):
    tenants = Person.objects.filter(home__address=house)
    return tenants

现在,您可以为每个组合查询创建一个视图:

views.py:

import helpers.py
from itertools import chain

def get_cars_of_tenants_or_johns(request, house):
    results = list(chain(get_cars_of_tenants(house), get_johns(house)))
    return render_to_response('cars_or_johns.html', {"results": results,})

def get_tenants_or_johns(request, house):
    results = list(chain(get_tenants(house), get_johns(house)))
    return render_to_response('tenants_or_johns.html', {"results": results,})

这可以用于所有各种组合。返回的是results,它是您可以迭代的所有匹配项的列表。