Django обновляет объекты m2m при сохранении

У меня есть rel m-2-m и я хочу обновить rel B после добавления любого rel A через страницу администратора.

Вот подробности:

У меня есть 2 модели, Матч (rel A) и Игрок (rel B). Я хочу обновлять Player.matches_played каждый раз, когда добавляется новый матч с этим игроком в Match.team1 или Match.team2.

Как я могу этого добиться???

модели

class Match(models.Model):
    data=models.DateField(auto_now_add=False,auto_now=False)
    team1=models.ManyToManyField('players.Player',related_name='team_1')
    team2=models.ManyToManyField('players.Player',related_name='team_2')
    score_team1=models.IntegerField(validators=[MinValueValidator(0)])
    score_team2=models.IntegerField(validators=[MinValueValidator(0)])

class Player(models.Model):
    matches_played= models.IntegerField(validators=[MinValueValidator(0)], default=0)

Я пробовал сигналы, но в post_save сигнал {instance.team1} или instance.team1.all() возвращают пустой QuerySet, что я считаю правильным, так как M2M rel сохраняется позже. Затем я попробовал m2m_changed, но этот сигнал не срабатывает при сохранении через страницу администратора. Что я упускаю?


@receiver(post_save, sender=Match, dispatch_uid="update_player_game_count")
def update_player_games(sender, instance, created, **kwargs):
    print(f'created {instance.pk}')
    print(f'created {instance.team1}')
    print(f'created {instance.team2}')
    print(f'created {instance.score_team1}')
    print(instance.team1.all())
@receiver(m2m_changed, sender=Match, dispatch_uid="update_player_game_count")
def update_player_game(sender, instance, created, action, **kwargs):
    print(action)
    if action == 'post_add':
        print(action)

Большое спасибо за помощь

альтернатива, о которой я думал, это получать данные через свойство в Player, например, так, но я думаю, с точки зрения производительности, лучше обновлять строки каждый раз, когда добавляется матч, а затем считать матчи каждый раз, когда запрашивается игрок

Пример

@property
def matches_played(self):
    return Match.objects.filter(team1__nome=self.nome).count()+Match.objects.filter(team2__nome=self.nome).count()

Отправителем сигнала m2m_change [Django-doc] является не Match, а Match.team1.through, и/или Match.team2.through, поэтому:

@receiver(
    m2m_changed,
    sender=Match.team1.through,
    dispatch_uid='update_player_game_count1',
)
@receiver(
    m2m_changed,
    sender=Match.team2.through,
    dispatch_uid='update_player_game_count2',
)
def update_player_game(sender, instance, created, action, **kwargs):
    print(action)
    if action == 'post_add':
        print(action)

При этом хранить количество сыгранных матчей в качестве поля в модели не имеет особого смысла. Мы можем определить его при необходимости с помощью:

from django.db.models import Count

Player.objects.annotate(
    total_matches=Count('team1', distinct=True) + Count('team2', distinct=True)
)

Furthermore I don't think using two ManyToManyFields is per se the best modeling here. You might want to use a single ManyToManyField with a through=… model [Django-doc] that determines if the player played for the first or second team.

Вернуться на верх