Как реализовать автоматическое создание записей по полю 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>.

UPD Обновил модели

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(upload_to='users/achievements', default='static/achievement/achiv.jpg')
    
class User(BaseUser, models.Model):
    objects = BaseUserManager()
    picture_profile = models.ImageField(upload_to='users/users_picture_profile', null=True, blank=True,                                    default='static/picture_profile/pp.jpg')
    is_organization = models.BooleanField(default=False)
    achievements = models.ManyToManyField(to=UserAchievement, blank=True)

class UserAchievesStatus(models.Model):
    user = models.ForeignKey(to=User, on_delete=models.CASCADE)
    achievement = models.ForeignKey(to=UserAchievement, on_delete=models.CASCADE)
    is_achieved = models.BooleanField(default=False)

теперь пишу сигнал -

@receiver(post_save, sender=User)
def create_user_achievements(sender, instance, created, **kwargs):
    print('signal working')
    if created:
        print(instance.email)
        achievements = UserAchievement.objects.all()
        print(achievements)
        instance.achievements.add(*achievements)
        print(instance.achievements)

сигнал срабатывает но с ошибкой -

signal working
[email protected]
<QuerySet [<UserAchievement: название - Тест, опыт - 10>, <UserAchievement: название - Тест2, опыт - 2>]>
custom_user.UserAchievement.None

и вот проверяю еще раз в консоли

user = User.objects.last()
user
<User: [email protected]>
user.achievements.all()
<QuerySet []>

Когда делаю вручную через админку введите сюда описание изображения

все работает корректно

user = User.objects.last()
user
<User: [email protected]>
user.achievements.all()
<QuerySet [<UserAchievement: название - Тест, опыт - 10>, <UserAchievement: название - Тест2, опыт - 2>]>

Ответы (2 шт):

Автор решения: Allito

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

→ Ссылка
Автор решения: gajin

Для того, чтобы автоматически создавать обьекты 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

→ Ссылка