Условное массовое_создание или массовое_обновление полей экземпляра модели на основе условного равенства двух связанных по внешнему ключу полей в 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
Matchup.objects.filter(foo=foo).select_related('home_team__division', 'home_team__conference', 'away_team__division', 'away_team__conference'