Coder’s Eye

A site about one of the three passions in my life.

Coder’s Eye header image 2

Django auto_now Removal Gotcha

May 6th, 2007 · 2 Comments

DjangoThe latest Django revisions have removed the shortcut handlers "auto_now&quot 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.

Tags: Tips · Django · Python

Bookmark this article

del.icio.us:Django auto_now Removal Gotcha digg:Django auto_now Removal Gotcha spurl:Django auto_now Removal Gotcha wists:Django auto_now Removal Gotcha simpy:Django auto_now Removal Gotcha newsvine:Django auto_now Removal Gotcha blinklist:Django auto_now Removal Gotcha furl:Django auto_now Removal Gotcha reddit:Django auto_now Removal Gotcha fark:Django auto_now Removal Gotcha blogmarks:Django auto_now Removal Gotcha Y!:Django auto_now Removal Gotcha smarking:Django auto_now Removal Gotcha magnolia:Django auto_now Removal Gotcha segnalo:Django auto_now Removal Gotcha gifttagging:Django auto_now Removal Gotcha

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