views:

563

answers:

2

hello,

I'm trying to immediately update a record after it's saved. This example may seem pointless but imagine we need to use an API after the data is saved to get some extra info and update the record:

def my_handler(sender, instance=False, **kwargs):
    t = Test.objects.filter(id=instance.id)
    t.blah = 'hello'
    t.save()

class Test(models.Model):
    title = models.CharField('title', max_length=200)
    blah = models.CharField('blah', max_length=200)

post_save.connect(my_handler, sender=Test)

So the 'extra' field is supposed to be set to 'hello' after each save. Correct? But it's not working.

Any ideas?

+1  A: 

Doesn't the post_save handler take the instance? Why are you filtering using it? Why not just do:

def my_handler(sender, instance=False, created, **kwargs):
  if created:
     instance.blah = 'hello'
     instance.save()

Your existing code doesn't work because it loops, and Test.objects.filter(id=instance.id) returns a query set, not an object. To get a single object directly, use Queryset.get(). But you don't need to do that here. The created argument keeps it from looping, as it only sets it the first time.

In general, unless you absolutely need to be using post_save signals, you should be overriding your object's save() method anyway.

Paul McMillan
I actually tried that also to no avail. but if the people above are correct, I can't do this anyway since it will just get stuck in a post_save loop.
givp
Try it using the created flag. I think that should fix your problem, because created is unset on subsequent loops through.
Paul McMillan
You might want to look at this question for more info on when to use signals and when to override save: http://stackoverflow.com/questions/170337/django-signals-vs-overriding-save-method
Paul McMillan
doh! I had the truth value of test for the created flag set wrong for a bit. It should work now...
Paul McMillan
A: 

When you find yourself using a post_save signal to update an object of the sender class, chances are you should be overriding the save method instead. In your case, the model definition would look like:

class Test(models.Model):
    title = models.CharField('title', max_length=200)
    blah = models.CharField('blah', max_length=200)

    def save(self, force_insert=False, force_update=False):
        if not self.blah:
            self.blah = 'hello'
        super(Test, self).save(force_insert, force_update)
ozan
If he's doing this to the admin models, post_save is a better solution than subclassing the existing admin models and overriding save.
Paul McMillan