The Problem with auto_now and auto_now_add in Django.
auto_now
and auto_add_now
are attributes to Django DateTimeField
methods.
auto_now
changes the field to timezone.now
whenever the field is saved, auto_now_add
on the other hand only updates the field once when it is created.
Let’s say you have created a model like this:
class TimeTest(models.Model):
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
Now, for some reasons, you want to update the created
field in your model - You Can’t.
So you think, what can I do, you do some googling, and find that there’s a property called editable.
So you set created.editable = True
, and voila it works. In your Django Admin panel the created field is now editable.
What’s the problem then?
Addressing the Issue
When you try to update the model, and rerun the makemigration
or migrate
commands, you get an error saying
del kwargs['editable']
KeyError: 'editable'
This is because you can’t make the DateTimeField
editable in the model, so when you try to makemigrate
your model, python throws tantrums.
In my opinion, this has been done to prevent accident changes to data that are supposed to store the DateTime of object creation. However, you can change this time - after migrating your models, you can just change the field to be editable,
# Uncomment for testing purposes only
# Causes key error while migration because auto_now_add is uneditable by default
created.editable = True
Then you can change the fields now. When you’re done you can change the model back to its original state.
A Better Solution?
When you encounter this problem, you may want to rethink whether you truly want the field to have auto_now_add
as well as editable=True
. If the answer is no, then great, fix your model.
If yes, then you need some workaround. One of the most common ways is to entirely avoid auto_now_add and instead pass the time of object creation explicitly. This way you can control the time easily. Another solution is to create a new data type that inherits from Django DataTimeField
and modify as per your needs as discussed here https://stackoverflow.com/a/1737078/4748060.