我正在尝试覆盖模型上的save方法,以便生成唯一的第二个自动递增ID。
我创建了我的类并覆盖了save()方法,但由于某种原因它出错并出现以下错误:
TypeError: %d format: a number is required, not NoneType
以下是代码:
class Person(models.Model):
target = models.OneToOneField(Target)
person = models.OneToOneField(User)
gender = models.CharField(max_length=1)
gender_name = models.CharField(max_length=100)
person_id = models.CharField(max_length=100)
def save(self, *args, **kwargs):
self.person_id = "%07d" % self.id
super(Person, self).save(*args, **kwargs)
是因为我没有通过id参数而且还没有保存吗?无论如何都要从id生成一个值?
答案 0 :(得分:3)
实现所需内容的最安全,最简单的方法是使用post_save
信号,因为它在调用save
之后但在事务提交到数据库之前被触发。
from django.dispatch import receiver
from django.db.models.signals import post_save
@receiver(post_save, sender=Person)
def set_person_id(sender, instance, created, **kwargs):
if created:
instance.person_id = "%07d" % instance.id
instance.save()
答案 1 :(得分:0)
是的,在某些情况下,self.id将为None
,然后分配将失败。
但是,正如评论中所建议的那样,您不能只是分配和调用super
,因为那样您就不会将分配持久保存到数据库层。
您需要检查模型是否具有ID,然后以不同方式进行操作:
def save(self, *args, **kwargs):
if not self.id: # Upon instance creation
super(Person, self).save(*args, **kwargs) # Acquire an ID
self.person_id = "%07d" % self.id # Set the person_id
return super(Person, self).save(*args, **kwargs)
这会向数据库发出两个保存操作。您需要将它们包装在事务中以确保数据库同时接收这两个字段。
from django.db import IntegrityError, transaction
class Person(models.Model):
target = models.OneToOneField(Target)
person = models.OneToOneField(User)
gender = models.CharField(max_length=1)
gender_name = models.CharField(max_length=100)
person_id = models.CharField(max_length=100)
def create_person_id(self):
if not self.id: # Upon instance creation
super(Person, self).save(*args, **kwargs) # Acquire an ID
self.person_id = "%07d" % self.id
def save(self, *args, **kwargs):
try:
with transaction.atomic():
self.create_person_id
return super(Person, self).save(*args,**kwargs)
except IntegrityError:
raise # or deal with the error
答案 2 :(得分:0)
我同意信号可能是更好的选择,如果没有,请尝试使用pk而不是id。
class Person(models.Model):
# [ . . . ]
def save(self, *args, **kwargs):
self.person_id = "%07d" % self.pk
super(Person, self).save(*args, **kwargs)