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

Kry*_*ski 0 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)
Run Code Online (Sandbox Code Playgroud)

假设我需要(尽管很奇怪)获得:

  • 住在房子里或名为“约翰”的人的名单
  • 以上人士的汽车清单

我想要两个功能:

  • 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)
Run Code Online (Sandbox Code Playgroud)

问题是在上面的例子中重复了逻辑。如果我可以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))
Run Code Online (Sandbox Code Playgroud)

为此,get_tenants_or_johns(house)需要返回查询集的联合,而不将它们转换为其他集合。

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

Kry*_*ski 5

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

该函数需要更改为(去掉set()包装器):

def get_tenants_or_johns(house):
    johns = Person.objects.filter(name='John')
    tenants = house.tenants.all()
    return johns | tenants
Run Code Online (Sandbox Code Playgroud)

一切都会像需要的那样工作。