1

假设我有以下模型:

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)

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

  • 住在房子里或被命名为“约翰”的人的名单
  • 上述人员的汽车清单

我想要两个功能:

  • 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)返回 aqueryset我可以定义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。有没有办法做到这一点?如果没有,是否有另一种方法来实现我想要做的事情?

4

2 回答 2

9

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

该功能将需要更改为(摆脱set()包装器):

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

一切都将完全按照需要进行。

于 2013-01-09T15:12:26.993 回答
0

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

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

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

助手.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

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

视图.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您可以迭代的所有匹配项的列表。

于 2013-01-09T05:12:27.627 回答