Python 创建表示查询集并集的查询集

Python 创建表示查询集并集的查询集,python,django,django-orm,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

假设我有以下模型:

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)
假设我需要(尽管很奇怪)得到:

  • 住在房子里或被称为“约翰”的人的名单
  • 上述人员的车辆清单
我想有两个功能:

  • 找租户或约翰(房子)
  • 从租户或约翰(房子)那里获得汽车。
我可以将其定义为:

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)
问题在于上述示例中重复了该逻辑。如果我可以获取
获取租户或约翰(房屋)
以返回
查询集
我可以将
获取租户或约翰(房屋)的汽车定义为:

def get_cars_of_tenants_or_johns(house):
    return Car.objects.filter(owner__in=get_tenants_or_johns(house))
为了做到这一点,
get_tenants\u或_johns(house)
需要返回一个querysets的联合,而不将它们转换为其他集合


我不知道如何实现
获取租户或约翰(房子)
,以便返回包含SQL
联合的查询集。有办法吗?如果没有,是否有其他方法来实现我的目标?

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

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

但是为了回答您的问题,让我们设置三个助手函数。因为,正如我上面提到的,您没有概述您想要对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
,它是您可以迭代的所有匹配项的列表。

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

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

但是为了回答您的问题,让我们设置三个助手函数。因为,正如我上面提到的,您没有概述您想要对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
,它是您可以迭代的所有匹配项的列表。

两个查询集上的
|
操作符将返回表示联合的新查询集

函数需要更改为(去掉
set()
wrappers):


所有操作都将按照需要进行。

两个查询集上的
操作符将返回一个表示联合的新查询集

函数需要更改为(去掉
set()
wrappers):


一切都将按照需要进行。

感谢您的反馈。这是一个深夜的问题,我写了很多错字。我不是指用户对象,而是指个人对象。我已经修改了这个问题。不幸的是,你的建议
租户+约翰
不起作用,尽管我非常希望它能起作用。它为+:“QuerySet”和“QuerySet”抛出一个不受支持的操作数类型。虽然我最初的问题听起来很傻,但它与我在职业上面临的问题类似(这更复杂,但需要类似的功能)。我希望它没有被否决,因为这是一个有效的问题。我编辑了我的帖子,使用itertools
chain
来组合查询集。请试一试。为了更深入地了解为什么/如何工作,我建议查看itertools文档和这篇文章:我已经找到了我想要的答案。它是查询集上的
|
运算符。这正是我所需要的。对我来说,重要的是将上述函数返回的查询集作为查询集,而不是将它们转换为列表、集合或其他容器。这样,我就可以在这些查询集上调用
.delete()
.count()
。感谢您的反馈。这是一个深夜的问题,我写了很多错字。我不是指用户对象,而是指个人对象。我已经修改了这个问题。不幸的是,你的建议
租户+约翰
不起作用,尽管我非常希望它能起作用。它为+:“QuerySet”和“QuerySet”抛出一个不受支持的操作数类型。虽然我最初的问题听起来很傻,但它与我在职业上面临的问题类似(这更复杂,但需要类似的功能)。我希望它没有被否决,因为这是一个有效的问题。我编辑了我的帖子,使用itertools
chain
来组合查询集。请试一试。为了更深入地了解为什么/如何工作,我建议查看itertools文档和这篇文章:我已经找到了我想要的答案。它是查询集上的
|
运算符。这正是我所需要的。对我来说,重要的是将上述函数返回的查询集作为查询集,而不是将它们转换为列表、集合或其他容器。这样,我就可以对这些查询集调用
.delete()
.count()