Как бы я сделал эти множественные объединения как набор запросов Django? - PullRequest
0 голосов
/ 26 апреля 2018

У меня есть этот запрос, который объединяет несколько таблиц:

select 
    p.player_id
    , d.player_data_1
    , l.year
    , l.league
    , s.stat_1
    , l.stat_1_league_average
from 
    stats s
inner join players p on p.player_id = s.player_id
left join player_data d on d.other_player_id = p.other_player_id
left join league_averages as l on l.year = s.year and l.league = s.year
where 
    p.player_id = 123

Мои модели выглядят так:

class Stats(models.Model):
    player_id = models.ForeignKey(Player)
    stat_1 = models.IntegerField()
    year = models.IntegerField()
    league = models.IntegerField()


class Player(models.Model):
    player_id = models.IntegerField(primary_key=True)
    other_player_id = models.ForeignKey(PlayerData)

class PlayerData(models.Model):
    other_player_id = models.IntegerField(primary_key=True)
    player_data_1 = models.TextField()

class LeagueAverages(models.Model):
    year = models.IntegerField()
    league = models.IntegerField()
    stat_1_league_average = models.DecimalField()

Я могу сделать что-то вроде этого:

Stats.objects.filter(player_id=123).select_related('player')

сделать первое присоединение. Для второго соединения я попробовал:

Stats.objects.filter(player_id=123).select_related('player').select_related('player_data')

но я получил эту ошибку:

django.core.exceptions.FieldError: Недопустимые имена полей, указанные в select_related: 'player_data'. Выборы: игрок

Как бы я сделал третье соединение, учитывая, что year и league не являются внешними ключами ни в одной из таблиц? Спасибо!

1 Ответ

0 голосов
/ 26 апреля 2018

select_related (* fields) Возвращает QuerySet, который будет «следовать» отношениям внешнего ключа, [...]

Согласно документации на django select_related следует отношениям с внешним ключом. player_data является соседним внешним ключом или даже полем Stats. Если вы хотите INNER присоединиться PlayerData и Player, вы можете следовать его внешним ключам. В вашем случае используйте двойное подчеркивание , чтобы добраться до PlayerData:

Stats.objects.all()
    .select_related('player_id')
    .select_related('player_id__other_player_id')

Что касается присоединения LeagueAverages: Нет способа объединить модели без соответствующего внешнего ключа, но использовать raw sql. Посмотрите на связанный вопрос: Запрос Django JOIN без внешнего ключа . Используя .raw(), ваше ЛЕВОЕ объединение (что, кстати, тоже не так просто без использования raw: Пользовательское левое внешнее соединение Django ) также может быть учтено.

Краткие заметки о ваших моделях:

  1. Каждая модель по умолчанию имеет автоматически увеличивающийся первичный ключ, доступ к которому можно получить с помощью .id или .pk. Таким образом, нет необходимости добавлять, например, player_id
  2. Поле models.ForeignKey ссылается на объект, а не на его идентификатор. Поэтому более интуитивно понятно переименовать, например, player_id в player. Если вы называете свое поле player, django позволяет автоматически получить доступ к его идентификатору через player_id
...