The latest Django revisions have removed the shortcut handlers "auto_now" and "auto_now_add". This didn’t look like a very big deal to replace. I simply did what was suggested in a django-users thread.
The problem was that after I did that, my live code seemed to work fine, but my test cases had several repeatable errors that I just couldn’t reproduce on the live server or at the command line.
The Fix
The fix involves overriding the "save" method, like so (quoting the thread)
class MyModel(models.Model):
self.created = models.DatetimeField()
self.modified = models.DatetimeField()
def save(self):
if not self.id:
self.created = datetime.datetime.now()
else:
self.modified = datetime.datetime.now()
super(MyModel, self).save()
What went wrong
After a lot of debugging and shrewd guessing, I finally had the eureka moment. The problem is that some of the test code was directly instantiating objects via calls like MyModel.objects.get_or_create(name="this", field="that"). In some places the test cases were using the even simpler MyModel.objects.create(name="this", field="that").
It finally occurred to me while walking the dog this morning that creating objects this way will skip the overridden "save()" method. I rushed to the computer to test my theory, and found that if I replaced:
MyModel.objects.get_or_create(name="this", field="that")
with this:
try:
m = MyModel.objects.get(name="this", field="that")
except MyModel.DoesNotExist:
m = MyModel(name="this", field="that")
m.save()
everything worked perfectly.
So, watch out for that gotcha now that you can’t use auto_now in models any more.
















2 responses so far ↓
1 Malcolm Tredinnick // May 7, 2007 at 5:53 pm
There’s something else going on here, I suspect. Both the create() and get_or_create() method do call your model’s save() method. In fact, get_or_create() is implemented more or less exactly as in your second example.
If you want to trace throught the code, MyModel.objects.get_or_create() calls django.db.models.manager.Manager.get_or_create() which just passes off the real work to django.db.models.query.QuerySet.get_or_create() and you can see that calling obj.save() when required.
So it would be interesting to understand what is really changing when you make the substitution you suggest above.
2 Ramin // Feb 24, 2008 at 10:03 am
Minor typo.
models.DatetimeField() should be models.DateTimeField() (with capitalized ‘T’).
Leave a Comment