created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True)
The problem I ran into was that I wanted to keep the legacy timestamp from the old database when I loaded the record for the first time then have the auto_now kick in. The problem is that auto_now is very stupid (as it should be) and doesn't understand the concept of insert or update and whether your new record is coming in with pre-populated DateTimeField attribute. It gladly throws away any value away and always replaces the value with the current time. I didn't notice it on first import but soon realized auto_now wouldn't meet my needs.
After a quick search, I found this Stack Overflow question that had the perfect fix for my problem. It suggested implementing my own save that would allow me to pass in values for created or modified but would fall back to the current time. I changed the code a bit because I didn't need a created timestamp for my model, but this should give you an idea.
Note: you have to remove any additional values from kwargs before passing to the parent class or super.save will complain that created and modified aren't valid arguments.
import datetime class User(models.Model): created = models.DateTimeField(editable=False) modified = models.DateTimeField() def save(self, *args, **kwargs): # original Code: called datetime.datetime.today() # multiple places. Modified kwargs # # created = kwargs.pop('created', None) # if created: # self.created = created # elif not self.id: # self.created = datetime.datetime.today() # # modified = kwargs.pop('modified', None) # if modified: # self.modified = modified # else: # self.modified = datetime.datetime.today() # Edit #1: Changed example to more efficient # version from blog comments. # single today() # # today = datetime.datetime.today() # # if not self.id # self.created = kwargs.pop('created', today) # elif kwargs.get('created', None) # self.created = kwargs.pop('created') # # self.modified = kwargs.pop('modified', today) # Edit #2: no longer pass arguments via save # was orignially how I wanted to solve # the problem and how I felt auto_now # should have worked. Thanks to # indosauros from reddit. :) # # On inital creation of the object # only set today if values are not # already populated. auto_now* # wipes them out regardless today = datetime.datetime.today() if not self.id: if not self.created: self.created = today if not self.modified: self.modified = today else: self.modified = today super(User, self).save(*args, **kwargs)
If you see any glaring python or style related issues, please let me know. I'm still finding my way pythonwise and would love any best practices feedback.