2015-10-14 48 views
0

我想覆盖模型上的保存方法以便生成唯一的第二个自动递增ID。重写保存方法在Django中创建第二个自动递增字段

创建我的类和重写保存()方法,但由于某种原因,它示数出来,出现以下错误:

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

只是改变顺序..调用超级之前的任务。 – karthikr

+0

此外,使用'post_save'信号代替覆盖'save()'方法可能会更好。 –

+0

该领域的目的是什么? –

回答

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

最安全和最简单的方式来实现你想要的东西,是因为它是正确的save被称为解雇后使用post_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() 
+0

这会将OP发送给递归。是否有任何特别的理由给混音带来信号? –

+0

对不起,忘了添加对'created'的检查。 @SebastianWozny因为信号与save()方法在同一个事务中,并且比手动事务管理更容易使用。 – maryokhin

0

我同意信号可能是更好的选择,如果不是,请尝试使用pk而不是id。

class Person(models.Model): 
    # [ . . . ] 
    def save(self, *args, **kwargs): 
     self.person_id = "%07d" % self.pk 
     super(Person, self).save(*args, **kwargs)