Как вы присоединяетесь к двум таблицам в поле внешнего ключа с помощью django ORM?
Предположим, что у меня есть следующие модели:
class Position(models.Model):
name = models.CharField()
class PositionStats(models.Model):
position = models.ForeignKey(Position)
averageYards = models.CharField()
averageCatches = models.CharField()
class PlayerStats(models.Model):
player = models.ForeignKey(Player)
averageYards = models.CharField()
averageCatches = models.CharField()
class Player(models.Model):
name = models.CharField()
position = models.ForeignKey(Position)
Я хочу выполнить эквивалентный SQL-запрос с помощью django ORM:
SELECT *
FROM PlayerStats
JOIN Player ON player
JOIN PositionStats ON PositionStats.position = Player.position
Как мне сделать это с помощью django ORM? Запрос не совсем корректный, но идея состоит в том, что я хочу получить один запрос, используя django ORM, который дает мне PlayerStats
, объединенный с PositionStats
на основе позиции игрока.
Ответы
Ответ 1
Это не один запрос, но он довольно эффективный. Это делает один запрос для каждой таблицы и объединяет их в Python. Подробнее о prefetch_related
здесь: https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related
Player.objects.filter(name="Bob").prefetch_related(
'position__positionstats_set', 'playerstats_set')
Ответ 2
Я уже давно работаю с django, и у меня было довольно сложное время, чтобы понять, как присоединиться к таблице, но я думаю, что, наконец, понимаю, и я хотел бы передать это другим, чтобы они могли избежать разочарования что у меня было с ним.
Рассмотрим следующую модель .py:
class EventsMeetinglocation(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=100)
address = models.CharField(max_length=200)
class Meta:
managed = True
db_table = 'events_meetinglocation'
class EventsBoardmeeting(models.Model):
id = models.IntegerField(primary_key=True)
date = models.DateTimeField()
agenda_id = models.IntegerField(blank=True, null=True)
location_id = models.ForeignKey(EventsMeetinglocation)
minutes_id = models.IntegerField(blank=True, null=True)
class Meta:
managed = True
db_table = 'events_boardmeeting'
Здесь мы видим, что location_id в EventsBoardmeeting является внешним ключом для id в EventsMeetinglocation. Это означает, что мы должны иметь возможность запрашивать информацию в EventsMeetinglocation, проходя через EventBoardmeeting.
Теперь рассмотрим следующие views.py:
def meetings(request):
meetingData = EventsBoardmeeting.objects.all()
return render(request, 'board/meetings.html', {'data': meetingData })
Как указано много раз ранее, в других сообщениях, django заботится о соединениях автоматически. Когда мы запрашиваем все в EventsBoardmeeting, мы также получаем любую связанную информацию по внешнему ключу, но способ доступа к этому в html немного отличается. Мы должны пройти через переменную, используемую в качестве внешнего ключа, для доступа к информации, связанной с этим соединением. Например:
{% for x in data %}
{{ x.location_id.name }}
{% endfor %}
В приведенных выше ссылках ВСЕ имена в таблице, которые были результатом соединения по внешнему ключу. x по существу является таблицей EventsBoardmeeting, поэтому, когда мы обращаемся к x.location_id, мы получаем доступ к внешнему ключу, который дает нам доступ к информации в EventsMeetinglocation.
Ответ 3
select_related()
и prefetch_related()
- ваше решение. Они работают почти так же, но имеют определенную разницу.
select_related()
работает путем создания соединения SQL и включения полей связанного объекта в оператор SELECT. По этой причине select_related
получает связанные объекты в одном запросе базы данных. Но он работает только для отношения "один к одному" или "один ко многим". Например, below-
entry = Entry.objects.select_related('blog').get(id=5)
or
entries = Entry.objects.filter(foo='bar').select_related('blog')
prefetch_related()
, с другой стороны, выполняет отдельный поиск для каждого отношения и выполняет "объединение в Python. Это позволяет ему предварительно select_related
объекты "многие-ко-многим" и "многие-к-одному", что невозможно сделать с помощью select_related
. Поэтому prefetch_related
будет выполнять только один запрос для каждого отношения. Пример дан below-
Pizza.objects.all().prefetch_related('toppings')
Ответ 4
От django.db
импортное соединение. В вашем представлении содержится описание ниже:
cursor = connection.cursor()
cursor.execute("select * From Postion ON Position.name = Player.position JOIN
PlayerStats ON Player.name =
PlayerStats.player JOIN PositionStats ON Position.name = PositionStats.player")
solution = cursor.fetchall()