【问题标题】:Django save() always create a new objectDjango save() 总是创建一个新对象
【发布时间】:2019-09-20 02:09:48
【问题描述】:

我的应用中有这个模型,它旨在根据 save() 中添加的方法自动生成它的主键。
但是,对于每个对象,我都需要更新某些字段。现在,每当我在管理端(测试用例)进行更新时,它都会创建一条新的 PK 记录,而不是更新现有的记录。关于如何解决这个问题的任何想法?

class DeploymentTask(models.Model):
    deployment_id = models.CharField(
        'Deployment Task ID', primary_key=True, max_length=25, editable=False)
    title = models.CharField(max_length=100)
    current_status = FSMField('Current Status',
                              default=STATES[0], choices=STATES)
    site_id = models.ForeignKey(
        Site, related_name='+', on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    refuel_record = models.ManyToManyField(RefuelRecord)

    def __str__(self):
        """String for representing the Model object."""
        return self.deployment_id

    class Meta:
        db_table = 'rm_deployment_task'
        verbose_name_plural = 'Deployment Tasks'

    def get_absolute_url(self):
        return reverse('deployment_id-view', args=[str(self.deployment_id)])

    def save(self):
        today = datetime.datetime.now()
        ticket_count = DeploymentTask.objects.filter(
            created_at__year=today.year, created_at__month=today.month).count() + 1
        new_task_id = 'DPT-' + str(str(datetime.date.today().year)) + str(
            datetime.date.today().month).zfill(2) + str(
            datetime.date.today().day).zfill(2) + '-' + str(ticket_count).zfill(6)
        self.deployment_id = new_task_id
        super(DeploymentTask, self).save()

enter image description here

【问题讨论】:

  • 将用于创建deployment_id 的代码包装在if not self.pk 中。这样,如果 pk 已经分配,​​它不会重新计算它。
  • 注意:将update_fields 添加到您的super() 调用中是一个非常糟糕的主意,因为这意味着您永远无法保存任何其他字段。
  • 感谢您的意见。我设法通过不自定义 save() 方法并从我的模型中定义一个函数来修复它,该函数将生成该 id 并将此方法分配为我的 pk 的默认方法。

标签: django django-models django-admin


【解决方案1】:

这是我更新的代码,对我有用...

def make_id():
    today = datetime.datetime.now()
    ticket_count = DeploymentTask.objects.filter(
                created_at__year=today.year, created_at__month=today.month).count() + 1
    new_task_id = 'DPT-' + str(str(datetime.date.today().year)) + str(
            datetime.date.today().month).zfill(2) + str(
            datetime.date.today().day).zfill(2) + '-' + str(ticket_count).zfill(6)  
    return new_task_id
class DeploymentTask(models.Model):
    deployment_id = models.CharField(
        'Deployment Task ID', primary_key=True, max_length=25, editable=False, default=make_id)
    title = models.CharField(max_length=100)
    current_status = FSMField('Current Status',
                              default=STATES[0], choices=STATES)
    site_id = models.ForeignKey(
        Site, related_name='+', on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    refuel_record = models.ManyToManyField(RefuelRecord)

    def __str__(self):
        """String for representing the Model object."""
        return self.deployment_id

    class Meta:
        db_table = 'rm_deployment_task'
        verbose_name_plural = 'Deployment Tasks'

    def get_absolute_url(self):
        return reverse('deployment_id-view', args=[str(self.deployment_id)])

【讨论】:

    【解决方案2】:
    • 您总是在保存方法中将self.deployment_id 设置为新值。
    • Django 尝试执行 UPDATE ... WHERE deployment_id = %,但还没有具有此 ID 的记录(至少如果您在不同日期保存“旧”对象或具有不同的票数)
    • 如果你想更新deployment_id以外的字段,那么如果已经设置了self.deployment_id,就不要设置它。如果你想更新deployment_id,那么没有直接的方法可以做到这一点,因为它被用作主键(但你可以记住旧的pk并在save创建新对象后删除该对象)

    Django docs 中了解更多信息。

    【讨论】:

    • 您好 Imposeren,感谢您的回复。如您所见,PK 旨在根据一天中的时间和已经存在的对象数量自动生成。当我通过删除“自我”进行修改时。没有创建新记录,但我可以更新旧记录
    • 我的意思是:if not self.deployment_id: self.deployment_id = SOME_DT_BASED_STRING。但是您使用default=make_id 的示例做了类似的事情
    猜你喜欢
    • 2015-07-26
    • 1970-01-01
    • 2012-09-30
    • 2013-10-31
    • 1970-01-01
    • 1970-01-01
    • 2018-04-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多