1

I have a problem with Django Rest Framework. This app I'm building is Avatar. User can update his/her own avatar, then avatar auto save with my path I defined (/users_id/photoset_id/filename.png). So I make function to save like this code:

def avatar_file_path(instance, filename):
    ext = filename.split('.')[-1]
    filename = '%s.%s' % (instance.id, ext)
    return "users/%s/avatar/%s_%s" %(instance.user.id, instance.photoset.id, filename)

class Avatar(models.Model):
    user = models.ForeignKey(User, related_name='avatar_set', null=True)
    photoset = models.ForeignKey(PhotoSet, null=True, blank=True)
    primary = models.BooleanField(default=True)
    caption = models.TextField(blank=True, null=True)
    image = models.ImageField(max_length=1024, upload_to=avatar_file_path)
    is_public = models.BooleanField(_('is public'), default=True, help_text=_('Public photographs will be displayed in the default views.'))
    date_uploaded = models.DateTimeField(default=datetime.datetime.now)

    def save(self, force_insert=False, force_update=False, *args, **kwargs):
        # Make one primary Avatar
        if self.primary:
            avatars = Avatar.objects.filter(user=self.user, primary=True).exclude(id=self.id)
            avatars.update(primary=False)
        # Set default photoset
        if self.photoset is None:
            if not PhotoSet.objects.filter(user=self.user, photoset_type=3).exists():
                PhotoSet.objects.create(user=self.user, photoset_type=3, title='Profile Pictures')
                self.photoset = PhotoSet.objects.get(user=self.user, photoset_type=3)
            if PhotoSet.objects.filter(user=self.user, photoset_type=3).exists():
                self.photoset = PhotoSet.objects.get(user=self.user, photoset_type=3)
        # Model Save override 
        if self.id is None:
            saved_image = self.image
            self.image = None
            super(Avatar, self).save(*args, **kwargs)
            self.image = saved_image
        super(Avatar, self).save(force_insert, force_update, *args, **kwargs)

When I create serializers POST with Django Rest Framework:

class AvatarCreateUpdateSerializer(ModelSerializer):
    class Meta:
        model = Avatar
        fields = [
            'user',
            'image',
            'caption',
            'is_public',
        ]

It goes problem: enter image description here

Error Log Tracking in line: super(Avatar, self).save(force_insert, force_update, *args, **kwargs)

Why I face with this problem and how can I fix this? Thank you in advance!

KitKit
  • 8,549
  • 12
  • 56
  • 82

3 Answers3

3

You are calling two times the save() method on the base class on your Model:

Here:

 super(Avatar, self).save(*args, **kwargs)

And here:

 super(Avatar, self).save(force_insert, force_update, *args, **kwargs)

As the comment below says, you should be using update_or_create or get_or_create to handle case like this.

Clément Denoix
  • 1,504
  • 11
  • 18
  • 1
    And you can basically use update as well rather than saving it like that: https://stackoverflow.com/questions/6382806/django-save-update-on-duplicate-key – user1767754 Nov 22 '17 at 04:52
  • When I remove this line: super(Avatar, self).save(*args, **kwargs). I cant presave with avatar_id in path. File path come: users/1/avatar/1_None.jpg instead users/1/avatar/1_9.jpg (9 is avatar_id) – KitKit Nov 22 '17 at 04:54
  • @Clement Can you help me fix this line into get_or_create? Bro – KitKit Nov 22 '17 at 06:28
  • I suggest you try this for yourself first. Programming is best learnt by doing. After trying, if you are still stuck, post a new question and I will gladly help you. Good luck! – Clément Denoix Nov 22 '17 at 06:46
  • Thanks @ClémentDenoix. I will try – KitKit Nov 22 '17 at 06:48
0

Issue Fixed: Change super(Avatar, self).save(force_insert, force_update, *args, **kwargs) into super(Avatar, self).save(*args, **kwargs)

KitKit
  • 8,549
  • 12
  • 56
  • 82
0

The problem is that the save function gets passed "forced_insert=True" by the rest framework. As you are saving twice with the same data, it is trying to force an insert of the same primary key twice.

A solution is that after the first save is to reset that forced_insert by adding

kwargs['force_insert'] = False

before the second save. That will allow Django to use the update method, hence not try and create the same primary key twice.

dwagon
  • 501
  • 3
  • 9