我的模型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
字段旁边添加另一个字段。