Порядок в Django Qeryset по полю, не связанному напрямую с моделью - PullRequest
0 голосов
/ 18 октября 2019

У меня следующий дизайн модели:

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 принадлежит Harbour, а Harbour принадлежитдо City.

  • Не у всех городов есть гавань.

  • NearestCity - это таблица, в которой хранится информация о том, насколько близок город к остальной части города. города: weight - это десятичное значение, которое указывает, как далеко город от _near_city_. Чем меньше значение 'weight', тем ближе город к near_city. Например:

city     near_city      weight
----    ---------       ------
London   Rome           2.210103
London   Manchester     0.113134

Это означает, что Манчестер ближе к Лондону, чем Рим.

Проблема, которую нужно решить:

Дано имягород без каких-либо связанных с гаванью, например, Берлин, желающих вернуть все лодки из тех ближайших городов, у которых есть хотя бы одна связанная с гаванью. Набор запросов этой Лодки должен быть заказан по weight DESC.

Я действительно новичок с набором запросов django, и я попытался решить, используя annotate с subqueries, aggregations и т. Д., Но я не смогдостичь этого.

1 Ответ

1 голос
/ 18 октября 2019

Я бы попробовал 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 добавляет к ним префиксы имен приложений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...