在django中使用pre_save时取消保存模型

Alf*_*ang 21 python django signals

我有一个模特:

class A(models.Model):
    number = models.IntegerField()
Run Code Online (Sandbox Code Playgroud)

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

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

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

Alf*_*ang 19

请参阅我的另一个答案: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')
Run Code Online (Sandbox Code Playgroud)

  • 请注意,如果在查询集上使用use update,则不会触发此挂接.例如`MyModel.objects.filter(some_case = 1).update(someval = 2)`只是阻止使用它. (2认同)
  • 我需要这样做,但引发异常会破坏流程。我不想破坏流程。我也无法覆盖保存方法或使用 post_save。 (2认同)
  • 捕获“pre_save”中引发的异常的最佳位置在哪里?我想阻止保存,但不想导致 500 错误。 (2认同)

Séb*_*rez 8

我不确定你是否只能使用pre_save信号取消保存.但是您可以通过覆盖save方法轻松实现此目的:

def save(self):
    if some_condition:
        super(A, self).save()
    else:
       return   # cancel the save
Run Code Online (Sandbox Code Playgroud)

如@Raptor所述,调用者不知道保存是否成功.如果这是您的要求,请查看另一个强制呼叫者处理"非保存"情况的答案.


Sar*_*ser 5

如果数据始终来自表单,并且您可以直接测试是否应进行保存,请通过验证器发送。但请注意,来自后端的 save() 调用不会调用验证器。如果您也希望这些受到保护,您可以创建一个自定义字段,比如说,如果您运行测试并在该自定义字段的to_python() 方法class PrimeNumberField(models.SmallIntegerField)中引发异常,它将阻止保存。您还可以通过重写Field、Form 或Model上的任何其他方法来挂钩特定字段的验证。