2015-10-14 52 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)