使用 Model.objects.create() 时未调用 Django model save() 方法



我的模型Image中有一个主键ID CharField,我想为新创建的对象创建唯一的ID。我尝试通过覆盖模型的保存方法来实现这一目标:

    def save(self, *args, **kwargs):
        if not self.pk: # is created
            self.id = uuid.uuid4().hex
            while Image.objects.filter(id=self.id).exists():
                self.id = uuid.uuid4().hex
        return super().save(*args,**kwargs)

问题是,当我使用 Image.objects.create() 创建对象时,save()似乎没有被调用,它仅在我使用 image=Image(...) 创建对象然后调用 image.save() 时才调用。因此,除非指定,否则新创建的对象不会分配 id,这会导致 PostgreSQL 抛出non_unique primary key错误。

如何确保在调用Image.objects.create()时创建唯一 ID?

姜戈版本:1.11.3

更新:我意识到也没有调用被覆盖的 save(( 方法。事实证明,问题是我在迁移中调用了模型的save方法。正如本文所指出的,自定义模型方法在迁移中不可用。我必须将模型的保存方法复制到迁移文件中。

这通常无法完成。在 if 语句检查 ID 尚不存在和设置它之间,其他内容可能会添加具有该 ID 的新行。这就是使用其他解决方案的原因 - 数据库确保唯一的自动递增ID,或者唯一的可能性很小的UUID。

幸运的是,您可以使用其中一个。对于UUID,习惯就是假设它们是唯一的。

这样做的方法是设置一个返回唯一 ID 的函数作为字段的默认值:

def uuid_hex():
    return uuid.uuid4().hex
class YourModel(models.Model):
    id = CharField(unique=True, primary_key=True, default=uuid_hex, null=False)

在重写模型save方法时,应调用真正的save方法:

def save(self, *args, **kwargs):
    if not self.pk: # is created
        self.id = uuid.uuid4().hex
        while Image.objects.filter(id=self.id).exists():
            self.id = uuid.uuid4().hex
    super(Image, self).save(*args, **kwargs)

检查文档:重写预定义的模型方法

覆盖默认id也不是一个好主意。如果您需要另一个唯一字段用作 ID 之类的内容,那么我建议您在默认id字段旁边添加另一个字段。

最新更新