【问题标题】:Cancel saving model when using pre_save in django在 django 中使用 pre_save 时取消保存模型
【发布时间】:2014-07-19 22:12:04
【问题描述】:

我有一个模型:

class A(models.Model):
    number = models.IntegerField()

但是当我调用 A.save() 时,我想确保该数字是质数(或其他条件),否则应该取消保存指令。

那么如何取消pre_save信号接收器中的save指令呢?

@receiver(pre_save, sender=A)
def save_only_for_prime_number(sender, instance, *args, **kwargs):
    # how can I cancel the save here?

【问题讨论】:

  • 你必须覆盖模型的保存功能,正如@Sebastien所说

标签: python django signals


【解决方案1】:

我不确定您是否可以仅使用 pre_save 信号取消保存。但是您可以通过重写 save 方法轻松实现此目的:

def save(self):
    if some_condition:
        super(A, self).save()
    else:
       return   # cancel the save

正如@Raptor 所提到的,调用者不知道保存是否成功。如果这是您的要求,请查看other answer,它强制调用者处理“非保存”情况。

【讨论】:

  • 这看起来不错,但是调用者不知道保存不起作用!
  • 有没有办法在pre_save中设置保存条件?
  • 是的,而不是return 应该引发异常。
【解决方案2】:

如果数据始终来自表单,并且您对是否应该进行保存有一个简单的测试,请通过validator 发送它。但请注意,不会为源自后端的 save() 调用调用验证器。如果您希望这些也受到保护,您可以创建一个自定义字段,例如class PrimeNumberField(models.SmallIntegerField) 如果您运行测试并在该自定义字段的to_python() method 中引发异常,它将阻止保存。您还可以通过字段、表单或Model 上的overriding any of several other methods 挂钩特定字段的验证。

【讨论】:

  • 经过长时间的实践,我发现做一个validator来限制字段并且总是在full_clean之前保存是一个很好的架构。你的解决方案是最有启发性的。
【解决方案3】:

查看我的另一个答案:https://stackoverflow.com/a/32431937/2544762

这种情况是正常的,如果我们只是想阻止保存,抛出异常:

from django.db.models.signals import pre_save, post_save

@receiver(pre_save)
def pre_save_handler(sender, instance, *args, **kwargs):
    # some case
    if case_error:
        raise Exception('OMG')

【讨论】:

  • 请注意,如果您在查询集上使用 use update,则不会触发此挂钩。例如MyModel.objects.filter(some_case=1).update(someval=2) 只是防止使用它。
  • @AlfredHuang,有什么方法可以在更新查询集时引发错误?
  • @TheJKFever AFAK,没有直接的解决方案,因为查询集更新将在多行上使用一次 sql 更新。如果你想这样做,遍历查询集并一一更新。
  • 我认为您可以使用 post_save 信号来处理它以进行更新,因为它是在更新时调用的。因此,这两个信号的组合可能是正确的答案。
  • 我需要这样做,但引发异常会中断流程。我不想破坏流量。我也不能覆盖保存方法或使用 post_save。
猜你喜欢
  • 2017-04-07
  • 1970-01-01
  • 2019-09-09
  • 2021-05-14
  • 2012-03-16
  • 2013-07-12
  • 2014-01-03
  • 2023-03-23
  • 2021-07-10
相关资源
最近更新 更多