Как реализовать автоматическое создание записей по полю ManyToManyField:

Я хочу создать атчивки для юзера, для понимания вот сами таблички:

class User(BaseUser, models.Model):
objects = BaseUserManager()
is_organization = models.BooleanField(default=False)

class UserAchievement(models.Model):
name = models.CharField(max_length=128, unique=True)
description = models.CharField(max_length=256)
final_value = models.SmallIntegerField()
progress_right_now = models.FloatField(default=0)
given_exp = models.SmallIntegerField()
#image = models.ImageField()

class UsersAchievements(models.Model):
user = models.ManyToManyField(to=User)
achievement = models.ManyToManyField(to=UserAchievement)
is_achieved = models.BooleanField(default=False)

Сделал промежуточную табличку и для будущей логики нужное поле, чтобы позже проверять выполнена атчивка или нет, но вопрос в том, как бы правильней при создании юзера создавать ему записи в таблице UsersAchievements по всем существующим атчивкам, делать это сигналом пост_сев? или переопределить метод save модели юзер? Пытался реализовать 2 вариант, но сталкивался с ошибками

Direct assignment to the forward side of a many-to-many set is prohibited. Use user.set() instead. User' object has no attribute 'userachievements_set'

Потому хочу спросить как лучше правильнее и как именно это реализовать?

сейчас пробую сделать сигнал:

@receiver(post_save, sender=User)
def create_users_achievements(sender, instance, created, **kwargs):
    if created and not instance.usersachievements_set.exists():
        achievements = UserAchievement.objects.all()
        instance.usersachievements_set.set(achievements)

но возникает следующая ошибка -

TypeError at /admin/custom_user/user/add/
Field 'id' expected a number but got <UserAchievement: название - Тест, опыт - 20>.

Третья таблица лишняя. Ее Django сам создаст. Просто в поле user добавь поле m2m на модель ачивок

Для того, чтобы автоматически создавать обьекты achievements для созданого юзера через связь many2many, я решил использовать сигналы.

Например:

@receiver(post_save, sender=User)
def create_user_achievements(sender, instance, created, **kwargs):
    if created:
        all_achievements = UserAchievement.objects.all()
        for achievement in all_achievements:
            user_achievement_status = UserAchievementStatus.objects.create(
                user=instance,
                achievement=achievement,
            )
            instance.achievements.set([achievement])

Более подробно в документации Many-to-many relationships.

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