django 检查保存方法中的唯一约束

e5nszbig  于 2023-06-25  发布在  Go
关注(0)|答案(1)|浏览(137)

我有一个unique_together参数不起作用的模型。原因是大多数时候“client_repr”变量是在保存()方法上设置的。如果有人创建了一个具有相同('client_repr','task_type'...)组合时,模型不会检测到它,因为“client_repr”值在保存()方法结束之前都是null。
如何在保存()方法中调用唯一约束验证?

class Task(models.Model):
    client = models.ForeignKey(Client, related_name = 'tasks', on_delete = models.CASCADE)
    b_client = models.ForeignKey(BClient, related_name = 'tasks', on_delete = models.CASCADE, null = True, blank = True)
    client_repr = models.CharField(max_length = 100, null = True, blank = True)
    task_type = models.CharField(max_length = 100)
    task_description = models.CharField(max_length = 100)
    department = models.ForeignKey(Department, related_name = 'tasks', on_delete = models.CASCADE)
    extra_fields = models.ManyToManyField(ExtraField, blank = True)
    spot = models.BooleanField(default = False)

    class Meta:
        unique_together = (('client_repr', 'task_type', 'task_description', 'department'), )

    def __str__(self):
        return ' | '.join([f'{self.client_repr}', f'{self.task_description}', f'{self.task_type}'])

    def save(self, *args, **kwargs):
        if not self.b_client:
            self.client_repr = str(self.client)
        else:
            self.client_repr = str(self.b_client)

        super().save(*args, **kwargs)

我知道我可以做一个搜索(例如:if Task.objects.get(...):)但这是最django-pythonic的方式吗?

qzwqbdag

qzwqbdag1#

选项一:使用clean()

这并不是你直接要求的,但它通常更适合django,并且不需要像覆盖save()这样奇怪的事情

class Task(Model):

    def clean():
        # your code starts here
        if not self.b_client:
            self.client_repr = str(self.client)
        else:
            self.client_repr = str(self.b_client)
        # your code ends here

由于这个自定义的clean()在**django调用validate_unique()之前被调用,所以它应该可以满足你的要求。
详情请参阅官方文档。

选项二:继续执行save()中的所有操作

要检查唯一约束,可以执行以下操作:

from django.core.exceptions import ValidationError

def save(self, *args, **kwargs):
    ...  # your code that automatically sets some fields
    try:
        self.validate_unique()
        # self.full_clean()  # <- alternatively, can use this to validate **everything**, see my comments below
    except ValidationError:
        # failed
        # that's up to you what to do in this case
        # you cannot just re-raise the ValidationError because Django doesn't expect ValidationError happening inside of save()
    super().save(*args, **kwargs)

注意事项:

  • 只执行self.validate_unique()并不能保证先前在save()中更新的值是好的,并且不违反其他内容
  • self.full_clean()更安全,但会稍微慢一点(有多慢-取决于您拥有的验证器)

文档

Django documentation说道:
验证模型涉及四个步骤:

  • 验证模型字段- Model.clean_fields()
  • 将模型作为一个整体进行验证- Model.clean()
  • 验证字段唯一性- Model.validate_unique()
  • 验证约束- Model.validate_constraints()

所有四个步骤都是在调用模型的full_clean()方法时执行的。

相关问题