Подтвердить что ты не робот

Как вы присоединяетесь к двум таблицам в поле внешнего ключа с помощью 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 на основе позиции игрока.

4b9b3361

Ответ 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()