简体   繁体   中英

Django FileField move file following upload

There are several questions around this topic but not one that I've found that suits what I'm trying to do. I want to be able to upload a file to a model and save that file in a nice location using the model instance attributes like pk. I know that this stuff gets set after model.save() so I need to write a custom save to do this, but I can't figure it out. Here is what I have:

class UploadModel(models.Model):
    image = models.ImageField(upload_to='uploads')

    def save(self, *args, **kwargs):

        # Call standard save
        super(UploadModel, self).save(*args, **kwargs)

        if 'uploads' in self.image.path:

            initial_path = self.image.path

            # New path in the form eg '/images/uploadmodel/1/image.jpg'
            new_path = os.path.join(settings.MEDIA_ROOT, 'images', 
                self._meta.model_name, self.pk, os.path.basename(initial_path))

            # Create dir if necessary and move file
            if not os.path.exists(os.path.dirname(new_path)):
                makedirs(os.path.dirname(new_path))

            os.rename(initial_path, new_path)

            # Do something here to save the new file to the image field

            # Save changes
            super(UploadModel, self).save(*args, **kwargs)

What do I have to do to the image field to get it to reference this new file location, and set all the useful attributes to it like image.path , image.name , image.url etc?

The docs say that the above is all I should need to do but this just results in the image field pointing to a file that doesn't exist. I've looked at this related question and tried the snippet mentioned in one of the answers but I have not found a solution yet.

I figured it out after a lot of searching and finding this old documentation ticket that has a good explanation.

class UploadModel(models.Model):
    image = models.ImageField(upload_to='uploads')

    def save(self, *args, **kwargs):

        # Call standard save
        super(UploadModel, self).save(*args, **kwargs)

        if 'uploads' in self.image.path:

            initial_path = self.image.path

            # New path in the form eg '/images/uploadmodel/1/image.jpg'
            new_name = '/'.join(['images', self._meta.model_name, str(self.id), 
                path.basename(initial_path)])
            new_path = os.path.join(settings.MEDIA_ROOT, 'images', 
            self._meta.model_name, self.pk, os.path.basename(initial_path))

            # Create dir if necessary and move file
            if not os.path.exists(os.path.dirname(new_path)):
                makedirs(os.path.dirname(new_path))

            os.rename(initial_path, new_path)

            # Update the image_file field
            self.image_file.name = new_name

            # Save changes
            super(UploadModel, self).save(*args, **kwargs)

Now I read the docs for this it looks totally obvious :) but I do think the explanation could be made more descriptive. Hopefully this will save someone some time!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM