2

我遇到了使用标志来标记模型实例以供将来处理的问题。我有一堂课:

class MyModel(models.Model):
    processed = models.BooleanField(default=False)
    changed = models.DateTimeField(auto_now=True)
    # More fields.

    def save(self):
        self.processed = False
        super().save(*args, **kwargs)

然后我有一个管理命令:

class Command(BaseCommand):

    def handle(self, *args: Any, **kwargs: Any) -> None:
        models = MyModel.objects.filter(processed=False).order_by("changed")[:200]
        for model in models:
            # Do some processing
            model.processed = True
            model.save()

现在,很明显,当模型被保存时,它只是将实例重新标记为未处理。

我是 django 新手,所以我对模型生命周期和可用方法的了解非常有限。我一直在阅读文档,到目前为止还没有找到任何解决方案。

关于如何解决这个问题的任何想法?

4

1 回答 1

2

解决这个问题的最好方法可能是添加一个参数来忽略标记:

class MyModel(models.Model):
    processed = models.BooleanField(default=False)
    changed = models.DateTimeField(auto_now=True)
    # More fields.

    def save(self, *args, unset_processed=True, **kwargs):
        if unset_processed:
            self.processed = False
        super().save(*args, **kwargs)

然后在您的基本命令中,我们可以使用:

class Command(BaseCommand):

    def handle(self, *args: Any, **kwargs: Any) -> None:
        models = MyModel.objects.filter(processed=False).order_by("changed")[:200]
        for model in models:
            # Do some processing
            model.processed = True
            model.save(unset_processed=False)

但是请注意,批量创建、更新等将绕过对模型的调用.save(…)。因此,例如,如果您使用:

MyModel.objects.filter(pk__in=[1,4,2,5]).update(some_field=some_value)

例如不会调用该.save(…)方法。例如, [Django-doc].update(…)的文档指出:

最后,意识到update()在 SQL 级别进行更新,因此不会调用模型上的任何save()方法,也不会发出pre_saveorpost_save信号

(……)

如果您想为具有自定义方法的模型更新一堆记录 save(),请遍历它们并调用save(),如下所示:

for e in Entry.objects.filter(pub_date__year=2010):
    e.comments_on = False
    e.save()
于 2021-08-13T18:43:29.400 回答