Tom
Tom

Reputation: 2661

how to change the name of a file and the storage location on upload in django

I want to change an image name and it's storage location on upload.

I have

def name_func(instance, filename):
    blocks = filename.split('.')
    ext = blocks[-1]
    filename = "%s.%s" % (instance.id, ext)
    return filename

class Restaurant(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4)
    image_file = models.ImageField(upload_to=name_func,null=True)

class Bar(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4)
    image_file = models.ImageField(upload_to=name_func,null=True)

This uploads all the image files into the media folder and gives it the instance's id as a name.

Now I want the image files to be uploaded into two different subfolders. So I tried using the system filestorage:

fs_restaurant = FileSystemStorage(location='media/restaurant')
fs_bar = FileSystemStorage(location='media/bar') 

and then change the image_file field to:

image_file = models.ImageField(upload_to=name_func,null=True, storage=fs_restaurant)

and

image_file = models.ImageField(upload_to=name_func,null=True, storage=bar)

Now this saves the files in the correct folder structure, however, when I click on the links in the admin's panel it's not linked correctly. This is obviously to the name_func function, but I am wondering if there is a way to correct that? In the doc I couldn't find a naming function in storage class.

Any ideas on how to fix that ?

Upvotes: 2

Views: 2034

Answers (1)

A. J. Parr
A. J. Parr

Reputation: 8026

I think your problem is that you need to prepend the subfolder onto your file name and return that. In your database the filename should be the relative path to your file from the STATIC_URL or MEDIA_URL.

Here's an example I have where I generate a UUID for the filename and put it in a subfolder called app_images.

def unique_filename(instance, filename):
    path = 'app_images'
    filetype = os.path.splitext(instance.image.name)[1]
    new_filename = "{}{}".format(uuid.uuid4().hex, filetype)
    while AppImage.objects.filter(image__contains=new_filename).exists():
        new_filename = "{}{}".format(uuid.uuid4().hex, filetype)
    instance.filename = filename
    return os.path.join(path, new_filename)

Upvotes: 2

Related Questions