I'm running into a problem with using a flag to mark model instances for future processing. I have a class:
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)
Then I have a management command:
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()
Now, obviously when the model is saved, it's just going to re-mark the instance as unprocessed.
I'm new to django, so my knowledge of the model lifecycle and the available methods is pretty limited. I've been reading through the documentation and haven't found any solution so far.
Any ideas on how I could tackle this?
Probably the best way to solve this is by adding a parameter to ignore flagging this:
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)
Then in your base command, we can work with:
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)
Note however that creating, updating, etc. in bulk will circumvent calling .save(…)
on the models. So if you for example use:
MyModel.objects.filter(pk__in=[1,4,2,5]).update(some_field=some_value)
will for example not call the .save(…)
method. The documentation on .update(…)
[Django-doc] for example states:
Finally, realize that
update()
does an update at the SQL level and, thus, does not call anysave()
methods on your models, nor does it emit thepre_save
orpost_save
signals(…)
If you want to update a bunch of records for a model that has a custom
save()
method, loop over them and callsave()
, like this:for e in Entry.objects.filter(pub_date__year=2010): e.comments_on = False e.save()