Often people make use of
datetime.now as a default value to specify a field that stores when a record was created, so something like:
from datetime import datetime from django.db import models class Post(models.Model): created_on = models.DateTimeField(default=datetime.now)
Why is it a problem?
A field is by default editable and not optional. This thus means that if you construct a
fields = '__all__', then this will include the
created_on in the form. Normally we do not want to include this. While it is of course possible to create a
editable=False, but if later additional features arise, one needs to specify more attributes.
datetime.now() [python-doc] does not include a timezone. This thus means that the database will store the timestamp without timezone. If thus later the server works with a different timezone, it will render different timestamps.
If one makes use of the
freezegun [GitHub], then making use of
datetime.now directly will not work. Indeed, if we first define a reference to
now(), then freezing the time will not have impact:
>>> from datetime import datetime >>> from freezegun import freeze_time >>> nw = datetime.now >>> with freeze_time('1958-3-25'): ... print(nw()) ... print(datetime.now()) ... 2020-12-06 17:05:35.861048 1958-03-25 00:00:00
so tests with the freezegun will not work.
What can be done to resolve the problem?
DateField has a
auto_now_add=… parameter [Django-doc]. By setting this parameter to
True, you automatically use the current timestamp when you construct the model object. We thus can construct a
from django.db import models class Post(models.Model): created_on = models.DateTimeField(auto_now_add=True)
DateField have a
auto_now=… parameter [Django-doc] as well. This is a field that will each time take the current timestamp when you update the record, so this can be used for an