覆盖save方法以在Django中创建第二个自动递增字段

时间:2015-10-14 20:23:08

标签: python django

我正在尝试覆盖模型上的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生成一个值?

3 个答案:

答案 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)