所以我的问题来自对查询的复杂性的不了解。这个问题有一些背景故事。
这是一个汽车租赁和搜索网站,最初是我的个人项目。我正在为此使用Django 2.1,以及Postgres。
设置如下:我有一个汽车模型,它具有ID,类别,汽车类型,引擎等。其次,有一个地址表,我可以用它来处理各种事情。
我现在想做的是:
我想创建Google Ads专用的.csv文件。为了向用户显示“相关内容”,此文件需要带有聚合整数的特定列。含义:您已经看到了Car A,这是该地区相关或相似的汽车的选择:K,O和Q。
我从数据制作csv确实没有问题,但是我的问题在于构造查询以使其工作。第一步,有以下步骤:
cars = Car.objects
.select_all_related()
.only(
'id',
'name',
'address__city',
'address__city_area',
'images'
)
select_all_related
加入地址表,因为那是汽车所在的位置。这也使我的only()调用正常工作,因为我想提取特定字段
仅给我我想要的字段,因为无论如何我都不希望发送整个模型,所以这也可行。
因此选择并获取正确的数据不是问题,而是:
真正的问题:
以下代码应在表中创建一列。此列应具有相似区域(城市和城市区域)中汽车的汇总ID。不幸的是,这是我使用的Google Ads的要求。
def find_similiar_cars_in_same_city(cars: QuerySet):
"""Annotate the QuerySet with a field called similar_cars_ids containing
a list of ad IDs or None if there are none."""
similar_cars_queryset = Cars.objects.filter(
address__city=OuterRef('address__city'),
address__city_area=OuterRef('address__city_area'),
).exclude(id=OuterRef('id')).values_list(ArrayAgg('id'), flat=True)
# Hack: Remove GROUP BY that Django adds when adding ArrayAgg.
similar_cars_queryset.query.group_by = []
cars = cars.annotate(similar_cars_ids=Subquery(
similar_cars_queryset,
output_field=ArrayField(models.IntegerField())
))
return cars
这有点奏效。只是永远。您还可以看到我在代码中所做的注释,即annotate()实际上将我实际上不需要的分组。我在本地运行所有东西,即使只有10辆车也需要大约12秒。我不确定我是否有任何遗漏。它有点用,但对于较大的样本量将不起作用。我在一个大约有14000辆汽车的DB上运行了它,但是它从未完成。
所以总结一下:我想创建一个函数,在数据库中创建一个具有相似汽车ID的列。
任何人都有在何处提高效率的指针?并且请问是否还有其他问题,我忘了提些什么!
答案 0 :(得分:0)
除非您对结果进行分页,否则在python中处理它可能会更容易。
cars = Car.objects
.select_all_related()
.only(
'id',
'name',
'address__city',
'address__city_area',
'images'
)
cars_in_area_map = defaultdict(set)
for car in cars:
cars_in_area_map[(car.address.city, car.address.city_area)].add(car.id)
# Generate csv:
data = [
car.id,
car.name,
car.address.city,
car.address.city_area,
car.image,
{id for id in cars_in_area_map[(car.address.city, car.address.city_area)] if id != car.id},
]
如果需要对它们进行分页,可以尝试通过地址进行操作:
data = []
addresses = Address.objects.prefetch_related('car_set')
for address in addresses:
cars = list(address.car_set.all())
for car in cars:
data.append([
car.id,
car.name,
address.city,
address.city_area,
car.image,
{c.id for c in cars if c.id != c},
])