Django,如何在调用super()后在save()方法中更新模型?

1 投票
5 回答
10287 浏览
提问于 2025-04-17 23:03

我遇到了这样的问题。比如,我在我的模型类里有一个字段:

periodic_task = models.OneToOneField(PeriodicTask, null=True, blank=True)

我需要重写 save() 方法来设置这个字段的值:

def save(self, *args, **kwargs):
    super(PostTweetSet, self).save(*args, **kwargs)
    self.periodic_task = TaskScheduler.create(
        'tweets.tasks.post_next_tweet', self.interval.period,
        self.interval.every, args="[" + '"%s"' % str(self.pk) + "]")

你可以看到,self.periodic_task 是在实际调用 super() 方法之后被赋值的。我这样做是因为我需要有一个主键字段(我在 TaskScheduler 的创建方法中用到它)。另一方面,我需要在设置这个新字段后更新数据库表。如果我再次调用 super(),就会出现关于重复 ID 的错误。那么,我该怎么做才能让这个工作正常?或者我需要完全重新考虑我的做法吗?谢谢。

5 个回答

0

如果你不想使用信号,那为什么不把super()的结果存起来,然后直接返回这个结果,而不是每次都调用它呢?

def save(self, *args, **kwargs):
    run_task = False
    if not self.pk:
        run_task = True

    result = super().save(*args, **kwargs)

    if run_task:
        TaskScheduler.create(...)

    return result
0

你可以在自己重写的 save() 方法的最后调用 super()。下面是一个使用 slugify() 方法的例子。这个 slugify 方法的作用是把一个字符串转换成一个“短链接”,它会把所有字符变成小写,并把空格替换成短横线。以下是代码:

from django.template.defaultfilters import slugify

def save(self, *args, **kwargs):
    self.slug = slugify(self.title)
    super(Product, self).save(*args, **kwargs)
2

你可能想在 post_save 信号中做这个事情。

4

通过在模型中的 override save method 提供一些条件,我达到了相同的需求。

在这个问题中,需求是要在保存模型后更新 periodic_task 字段,所以我遵循了以下的伪代码结构:

class MyModel(models.Model):
    periodic_task = models.OneToOneField(PeriodicTask, null=True, blank=True)
    def save(self):
        super(Asset, self).save()
        if not self.periodic_task: # Checking if the section is not updated.
            self.periodic_task = #code to update the field.
            self.save() #again call the save.
6

我会用一个保存后的信号来处理这个问题。

如果你不能这样做,或者这样做不太合适,你可以把你的需求想成两种情况:

  • 如果你还没有主键,你需要先保存数据,然后获取主键。
  • 如果你已经知道主键了,你可以创建一个定期任务,然后调用父类的方法。

所以可以写成类似这样的(伪代码):

def save(...):
    if self.pk is None:
        super(...)
        self.save(...)    # Call ourselves -- but this time, we'll have a primary key!
    else:
        ... create your periodic task
        super(...)

撰写回答