Условное массовое_создание или массовое_обновление полей экземпляра модели на основе условного равенства двух связанных по внешнему ключу полей в Django

Я пытаюсь bulk_create или bulk_update экземпляры модели Matchup, где два ее поля зависят от равенства или отсутствия обратных отношений двух связанных полей.

У Matchup есть поля home_team и away_team, оба из которых являются полями ForeignKey. Есть также поля is_divisional и is_conference для обозначения того, проводится ли матч между командами одного дивизиона или конференции.

class Matchup(models.Model):
    home_team = models.ForeignKey(
        "teams.Team",
        on_delete=models.CASCADE,
        related_name="home_matchups",
    )
    away_team = models.ForeignKey(
        "teams.Team",
        on_delete=models.CASCADE,
        related_name="away_matchups",
    )
    is_divisional = models.BooleanField(default=False)
    is_conference = models.BooleanField(default=False)

Модель Team также имеет два поля ForeignKey, conference и division.

class Team(models.Model):
    conference = models.ForeignKey(
        "leagues.Conference",
        on_delete=models.CASCADE,
        related_name="teams",
    )
    division = models.ForeignKey(
        "leagues.Division",
        on_delete=models.CASCADE,
        related_name="teams",
    )

Итак, цель здесь - проверить, принадлежат ли Matchup.home_team и Matchup.away_team к одной конференции или дивизиону. Если да, то is_conference/is_divisional соответственно должны быть True.

Вот что у меня было изначально. Это работает, но приводит к сотням дублирующихся запросов. Я выполняю это bulk_update после массового создания всех объектов.

for matchup in matchup_objs:
    if matchup.home_team.division == matchup.away_team.division:
        matchup.is_divisional = True
    if matchup.home_team.conference == matchup.away_team.conference:
        matchup.is_conference = True
Matchup.objects.bulk_update(matchup_objs, ["is_divisional", "is_conference"])

В попытке уменьшить количество дублирующих запросов, я попробовал использовать выражение Case() во время bulk_create объектов следующим образом.

matchup_objs = Matchup.objects.bulk_create(
    [
        Matchup(
            home_team=home_team,
            away_team=away_team,
            is_conference=Case(
                When(home_team__conference=F('away_team__conference'), then=Value(True)),
                default=Value(False)
            ),
            is_divisional=Case(
                When(home_team__division=F('away_team__conference'), then=Value(True)),
                default=Value(False)
            ),
        )
        for matchup in matchups
    ]
)

Но я получаю FieldError: Joined field references are not permitted in this query. Я полагаю, что это происходит потому, что объединение не разрешено для операции bulk_create.

Я думал об использовании SubQuery() здесь на основе этого ответа, но я не уверен, как этого добиться, поскольку утверждение When() ожидает имя параметра, а home_team__conference поиск - это то, что вызывает FieldError.

Есть ли способ сделать это или мне нужно прибегнуть к необработанному SQL?

если связанные атрибуты не кэшируются, django будет обращаться к базе данных снова и снова для каждого атрибута, к которому вы обращаетесь в цикле

for matchup in matchup_objs:
if matchup.home_team.division == matchup.away_team.division:
    matchup.is_divisional = True
if matchup.home_team.conference == matchup.away_team.conference:
    matchup.is_conference = True

https://docs.djangoproject.com/en/4.1/ref/models/querysets/#django.db.models.query.QuerySet.select_related

Matchup.objects.filter(foo=foo).select_related('home_team__division', 'home_team__conference', 'away_team__division', 'away_team__conference'
Вернуться на верх