I have the following model design:
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)
A Boat
belongs to a Harbour
and a Harbour
belongs to a City
.
Not all Cities have a harbour related.
NearestCity
is a table where is stored how close is a city the rest of the cities: The weight
is a decimal value that indicates how far is city from _near_city_. The more smaller is the 'weight' value, the more close is city to near_city. For example:
city near_city weight
---- --------- ------
London Rome 2.210103
London Manchester 0.113134
It means that Manchester is closer to London than Rome.
Given a name of a city without any harbour related, for instance Berlin, a want to return all the boats of those closest cities that do have at least one harbour related. This Boat's queryset must be ordered by weight
DESC.
I am really newbie with django queryset and I tried to solved using annotate
with subqueries
, aggregations
, etc.. but I could not achieve it.
I would try raw sql . Something like this should work:
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
Remember to replace table names with actual table names from your DB because Django adds app name prefixes to them.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.