首页 > 解决方案 > 区分django M2M信号中更新和创建的动作

问题描述

我希望做到以下几点。创建新项目时,我想通知分配给该项目的每个人有一个新项目可用。

这是我的简化项目模型:

class SalesProject(models.Model):
    sales_project_name = models.CharField(max_length=100)
    userProfile = models.ManyToManyField('UserProfile', blank=True)
    history = HistoricalRecords(excluded_fields=['version', 'project_status'])

    def __str__(self):
        return self.sales_project_name

创建项目时,我将发出以下信号:

def CreateProjectNotification(sender, **kwargs):
    if kwargs['action'] == "post_add" and kwargs["model"] == UserProfile:

        for person in kwargs['instance'].userProfile.all():

            #some check here to prevent me from creating a notification for the creator or the project
            Notifications.objects.create(
                target= person.user,
                extra = 'Sales Project',
                object_url = '/project/detail/' + str(kwargs['instance'].pk) + '/',
                title = 'New Sales Project created')

我使用 m2m_changed.connect 而不是 post_save 的原因是因为我希望访问 M2M 字段 UserProfile 来发送通知。由于在创建时不会将对象添加到直通表中,因此我不能使用 post_save 而是必须跟踪直通表中的更改。

问题 话虽如此,只要调用了 save() 函数并且更改的模型是 UserProfile 模型,此信号就会运行。

这是有问题的,例如,我不希望在添加新用户时发送相同的消息。相反,我希望运行一个单独的信号来处理它。

除了使用 if else 来区分对象的创建和相关 M2M 对象的添加之外,还有其他方法吗?

标签: pythondjangodjango-signals

解决方案


您应该尽可能避免使用信号,因为它们是不好的做法,如此处所述

您应该覆盖模型的save()功能SalesProject并处理其中的任何逻辑。可以使用 来检查 aSalesProject是否已创建或更新self._state.adding

self._state.adding == True表示SalesProject已创建

self._state.adding == False表示SalesProject已更新

从而实现你想要的:

class SalesProject(models.Model):
    sales_project_name = models.CharField(max_length=100)
    userProfile = models.ManyToManyField('UserProfile', blank=True)
    history = HistoricalRecords(excluded_fields=['version', 'project_status'])

    def save(self, *args, **kwargs):
        if self._state.adding:  # check if object is created and not updated
            # your logic goes here i.e. create/delete (related) objects
        return super(SalesProject, self).save(*args, **kwargs)    

    def __str__(self):
        return self.sales_project_name

编辑

假设您创建了一个UserProfile对象,并希望SalesProject通过将其分配给对象的userProfile字段来将其添加为与对象的关系。要获取新创建UserProfile对象的任何值,必须首先将其保存到数据库中。

一个例子:

# SalesProject model class

def save(self, *args, **kwargs):
    if self._state.adding:
        user_profile = UserProfile.objects.create(someField=someValue)
        self.userProfile.add(user_profile)
    return super(SalesProject, self).save(*args, **kwargs)

UserProfile.objects.create()将使用您分配给字段的值创建一个新UserProfile的并将其保存到数据库中。

self.userProfile.add(user_profile)添加新创建并保存UserProfile为与刚刚创建的 ManyToManyField 的关系SalesProject


推荐阅读