【问题标题】:Distinguishing The actions of updating and creation in django M2M signals区分django M2M信号中更新和创建的动作
【发布时间】:2020-10-04 13:14:50
【问题描述】:

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

这是我的简化项目模型:

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 对象的添加之外,还有其他方法吗?

【问题讨论】:

  • 如果我理解正确,您想在创建新的SalesProject 时创建Notification
  • 是的!但问题是我希望通过 M2M 字段访问用户配置文件模型,这就是为什么我必须使用 m2m 更改方法
  • 我想做的第二件事是区分“更新”和“创建”,这是因为通过使用 m2m_change ,只要通过表发生更改,该函数就会运行,因此我无法区分该操作是“更新”还是“创建”

标签: python django django-signals


【解决方案1】:

您应该尽可能避免使用信号,因为 explained here 是不好的做法。

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

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 对象,并希望通过将其分配给userProfile 字段来将其添加为与SalesProject 对象的关系。要获取新创建的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 添加为与刚刚创建的 SalesProject 的 ManyToManyField 的关系。

【讨论】:

  • 似乎将所有代码放在 fhe save 方法中会使我的 models.py 变得非常复杂,因为我希望考虑到很多不同的条件。 (此处未显示)我相信这确实会影响可读性,所以我所做的是创建一个单独的信号文件夹,专门用于通知。有没有办法在信号中复制 self._state.adding ?话虽如此,我将同时探索将逻辑放入保存方法中
  • 保持save() 清洁度的一种方法是为检查创建函数并将它们导入模型中。据我所知,不可能在 m2m_changed 信号中复制self._state.adding。如果您坚持使用 m2m_changed 信号,This post 有一些解决方法
  • 嘿@Stevy,我在翻译上述内容以适应我的情况时遇到了麻烦。我认为 save() 方法可以解决,比如说在一个特定的更新中,我正在通过表添加一个新的 userProfile,我将如何获取这个值,因为在保存时它还没有出现
  • @neowenshun,我在答案中添加了一个编辑。让我知道它是否对您有帮助。
  • 好的,谢谢。我的应用程序的设置方式,userProfile 只是对项目的分配。但是,似乎为此,我需要传入表单数据以了解要添加到我的关系中的实例或 userProfile,您知道一种方法吗?
猜你喜欢
  • 2013-07-19
  • 2021-08-22
  • 2021-10-26
  • 2020-08-13
  • 2021-02-22
  • 1970-01-01
  • 1970-01-01
  • 2018-05-06
  • 2016-09-28
相关资源
最近更新 更多