我有以下模型设计:
class Boat(models.Model):
name = models.CharField(max_length=30, null=False)
harbour = models.ForeignKey(Harbour, null=True, on_delete=models.SET_NULL)
class Harbour(models.Model):
name = models.CharField(max_length=60)
city = models.ForeignKey(City, null=True, related_name='city_harbours', on_delete=models.SET_NULL)
class City(models.Model):
name = models.CharField(max_length=80)
county = models.CharField(max_length=30, null=True)
class NearestCity(models.Model):
city = models.ForeignKey(City, related_name='city', null=False, on_delete=models.CASCADE)
near_city = models.ForeignKey(City, related_name='near_city', null=False, on_delete=models.CASCADE)
weight = models.DecimalField(null=False, max_digits=25, decimal_places=20)
Boat
属于Harbour
,而Harbour
属于City
。
并非所有城市都有与之相关的港口。
NearestCity
是一个表,存储与其他城市的城市之间的距离:weight
是一个十进制值,指示 city 来自_near_city_。 “权重”值越小,城市与near_city的距离就越近。例如:
city near_city weight
---- --------- ------
London Rome 2.210103
London Manchester 0.113134
这意味着曼彻斯特比罗马离伦敦更近。
给出一个没有任何港口相关城市的名称,例如柏林,想要归还那些至少有一个港口相关城市的最近城市的所有船只。此Boat的查询集必须由weight
DESC排序。
我真的是django queryset的新手,我尝试将annotate
与subqueries
,aggregations
等一起使用来解决。但是我无法实现。
答案 0 :(得分:1)
我会尝试raw sql。这样的事情应该起作用:
city = selected_city_pk
sql = """
SELECT b.name, nc.weight, nc.near_city_id
FROM appname_nearestcity nc
JOIN appname_city c ON near_city_id = c.id
JOIN appname_harbour h ON near_city_id = h.city_id
JOIN appname_boat b ON h.id = b.harbour_id
WHERE nc.city_id = %s
ORDER BY nc.weight, b.name
"""
results = Boat.objects.raw(sql, [city,])
for r in results: print(r.id, r.name, r.weight, r.near_city_id)
# boat_id, boat_name, weight, near_city_id
>> 14 b-0-h-sochi-0 10 6
>> 15 b-0-h-sochi-1 10 6
>> 16 b-0-h-sochi-2 10 6
>> 17 b-1-h-sochi-2 10 6
>> 18 b-2-h-sochi-2 10 6
>> 11 b-0-h-rome-0 55 5
>> 12 b-1-h-rome-0 55 5
>> 13 b-2-h-rome-0 55 5
>> 4 b-0-h-brasilia-0 56 4
>> 7 b-0-h-brasilia-1 56 4
>> 10 b-0-h-brasilia-2 56 4
>> 5 b-1-h-brasilia-0 56 4
>> 8 b-1-h-brasilia-1 56 4
>> 6 b-2-h-brasilia-0 56 4
>> 9 b-2-h-brasilia-1 56 4
>> 1 b-0-h-beijin-0 93 2
>> 3 b-0-h-beijin-1 93 2
>> 2 b-1-h-beijin-0 93 2
请记住用数据库中的实际表名替换表名,因为Django向其添加了应用程序名称前缀。