3

I want to update one field of my model after post save. For that I am using post_save signal but when I try to save the model it always get trapped in some kind of infinite loop and in the end I am getting max, recursion depth error

My code is as follows :

class UserProfile(models.Model):
   . 
   .
  . 

def profile_thumbanil(sender, created, instance , **kwargs):
    profile = UserProfile.objects.get(id = instance.id)
    thumb = handlers.create_thumbanil(profile.image, profile.user_id)
    profile.thumbnail_image = thumb
    profile.save()

post_save.connect(profile_thumbanil, sender=UserProfile)

I don't know what's the error here. If anyone can tell me another way of saving the data after post_save then that will be also fine.

Thanks

Edit :

save() will not work in my case because I am creating the thumbnail of images and the script which I using resize the images which are already exist on server and thus untill the save() finished its work image will not be saved on server and thus I cannot resize it that's why I can only run my function after save() finished its work so that image will be saved on server and I can resize it.

I can use Update() when user try to save images via UI and in that case my function works because Image is already saved into db but when admin (django-admin) try to upload an image then issue comes. So I need to call my function in such a way that whenever django admin save/edit profile images I can call my function but as I said my function only works after actual save() finished its work.

Laurent Bristiel
  • 6,819
  • 34
  • 52
Inforian
  • 1,716
  • 5
  • 21
  • 42

3 Answers3

2

You can redefine save method of the model. It is more appropriate in your case than using signals because you modify the same instance.

Maybe this would be helpful: http://www.martin-geber.com/thought/2007/10/29/django-signals-vs-custom-save-method/

Eugene Soldatov
  • 9,755
  • 2
  • 35
  • 43
  • I tried that but it will not work in my case because I am creating the thumbnail of images and the script which I using resize the images which are already exist on server and thus untill the save() finished its work image will not be saved on server and thus I cannot resize it that's why I can only run my function after save() finished its work so that image will be saved on server and I can resize it. – Inforian Apr 10 '14 at 07:14
  • 4
    In that case you can do: UserProfile.objects.filter(id = instance.id).update(thumbnail_image = thumb) Signal will not be send. – Eugene Soldatov Apr 10 '14 at 07:20
  • 1
    Yeah that works , I completely forget the update() anyway you save my day :). Thanks a lot – Inforian Apr 10 '14 at 07:25
  • Above link is broken – temirbek Nov 17 '22 at 09:16
0

You can get the object using filter and then use the update method to save the corresponding field.

def profile_thumbanil(sender, created, instance , update_fields=["thumbnail_image"], **kwargs):
    profile = UserProfile.objects.get(id = instance.id)
    thumb = handlers.create_thumbanil(profile.image, profile.user_id)
    profile.update(thumbnail_image = thumb)

post_save.connect(profile_thumbanil, sender=UserProfile)

An alternative method is to disconnect the post save signal, save relevant fields then reconnect the post save method.

aliasav
  • 3,048
  • 4
  • 25
  • 30
0

We need to be super careful when using save() inside post_save, they can lead to a recursive call. Here is one solution.

def profile_thumbanil(sender, created, instance , update_fields=["thumbnail_image"], **kwargs):
    profile = UserProfile.objects.get(id = instance.id)
    thumb = handlers.create_thumbanil(profile.image, profile.user_id)
    profile.save(update_fields=["thumbnail_image"])

post_save.connect(profile_thumbanil, sender=UserProfile)

Internally this would use an update SQL command instead of insert.

UPDATE row
SET    "thumbnail_image" = 'your image'
WHERE  "row"."id" = pk

This will work for sure, however, the best practice would be to use save() method instead.

nofoobar
  • 2,826
  • 20
  • 24