Django admin file upload with current model id
The image file gets saved before Gallery instance. So you have to split the saving to two phases by using signals w/ Gallery instance itself carrying the state:
from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver
_UNSAVED_FILEFIELD = 'unsaved_filefield'
@receiver(pre_save, sender=Image)
def skip_saving_file(sender, instance, **kwargs):
if not instance.pk and not hasattr(instance, _UNSAVED_FILEFIELD):
setattr(instance, _UNSAVED_FILEFIELD, instance.image)
instance.image = None
@receiver(post_save, sender=Image)
def save_file(sender, instance, created, **kwargs):
if created and hasattr(instance, _UNSAVED_FILEFIELD):
instance.image = getattr(instance, _UNSAVED_FILEFIELD)
instance.save()
# delete it if you feel uncomfortable...
# instance.__dict__.pop(_UNSAVED_FILEFIELD)
The upload_path_handler looks like
def upload_path_handler(instance, filename):
import os.path
fn, ext = os.path.splitext(filename)
return "site_media/images/gallery/{id}{ext}".format(id=instance.pk, ext=ext)
I suggest using ImageField instead of FileField for type-checking if the field is for image uploading only. Also, you may want to normalize filename extension (which is unnecessary because of the mimetype) like
def normalize_ext(image_field):
try:
from PIL import Image
except ImportError:
import Image
ext = Image.open(image_field).format
if hasattr(image_field, 'seek') and callable(image_field.seek):
image_field.seek(0)
ext = ext.lower()
if ext == 'jpeg':
ext = 'jpg'
return '.' + ext
For Django 2.2, follow the below code.
def save(self, *args, **kwargs):
if self.pk is None:
saved_image = self.image
self.image = None
super(Gallery, self).save(*args, **kwargs)
self.image = saved_image
if 'force_insert' in kwargs:
kwargs.pop('force_insert')
super(Gallery, self).save(*args, **kwargs)
Add the above code snippet to your 'class Gallery'.
P.S.: This will work for DRF as well when you save via views.py. Note that second if (condition) is required for DRF.
I ran into the same problem. Okm's answer sent me on the right path but it seems to me it is possible to get the same functionality by just overriding the save()
method of your Model.
def save(self, *args, **kwargs):
if self.pk is None:
saved_image = self.image
self.image = None
super(Material, self).save(*args, **kwargs)
self.image = saved_image
super(Material, self).save(*args, **kwargs)
This definitely saves the information correctly.