首页 > 解决方案 > 使用 Django 信号捕获更改后更改实例值

问题描述

我有一个Course与我的模型具有多对多关系的CustomUser模型:

class CustomUser(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(_('Email Address'), unique=True)
    user_name = models.CharField(_('User Name'), max_length=150, unique=True)
    # and a lot of other fields and stuff


class Course(models.Model):
    enrolled_users = models.ManyToManyField(CustomUser, related_name="enrolls", blank=True)
    previous_enrolled_users = models.ManyToManyField(CustomUser, related_name="previous_enrolls", blank=True)
    course_name = models.CharField(_("Course Name"), max_length=200)

我想要实现的是,每当用户完成一门课程(因此用户从 中删除enrolled_users)时,我的应用程序就会将此用户存储在 中previous_enrolled_users,这样我就可以知道之前在该课程中注册的用户。

我已经实现了m2m_changed这样的信号监听:

def listen_m2mchange(sender, instance, model, pk_set, action, **kwargs):
    if action == 'pre_remove':
        # I'm trying to guess what to do

m2m_changed.connect(listen_m2mchange, sender=Course.enrolled_users.through)

这样,每当我从课程中删除用户时,Django 都会发出信号m2m_changed并且我会捕获该信号。我知道这instanceCourse该类的实例,那是我要删除model的那个类的实例。CustomUser我无法猜测的是,如何使用Course类的实例将其添加CustomUser到previous_enrolled_users 中。任何帮助将不胜感激。

编辑 01:

阅读了很多文档,我知道我想要做的是每次model都从以下内容中删除enrolled_users

instance.previous_enrolled_users.add(model)

但是当我这样做时,我得到一个错误:

TypeError: Field 'id' expected a number but got <class 'core.models.CustomUser'>.

标签: python-3.xdjangodjango-modelsmany-to-manydjango-signals

解决方案


试试这个:

def listen_enrolled_users_m2mchange(sender, instance, model, pk_set, action, **kwargs):
    if action == 'post_remove':
        instance.previous_enrolled_users.add(*pk_set)

m2m_changed.connect(listen_enrolled_users_m2mchange, sender=Course.enrolled_users.through)

pk_set这里将是一组主键,这些主键参与enrolled_usersCourse. 这意味着当 action 为 时post_remove,所有删除的CustomUser主键都将在pk_setkwarg 中传递。

这意味着当信号开始改变enrolled_usersof 时Course,我们可以检查该操作是否为移除。在这种情况下,pk_set我们收到的被删除的相同内容enrolled_users可以直接添加到 previous_enrolled_users.


推荐阅读