Nathan Welsh
Nathan Welsh

Reputation: 17

Trouble with media directory/files on pythonanywhere

I seem to be having an issue serving up media content on my website. Everything works fine when run on localhost. However, when deployed to python anywhere, I receive a FileNotFoundError when I attempt to upload an image via a form. I've taken a look through overflow for some related topics however I've not found any threads which have allowed me to solve my problem.

Here is the exact error received when submitting the image upload form:

pythonanywhere error message stack trace of error
It seems to be an issue with the resize method in models.py (which works fine on localhost)

Here are the appropriate setup files: settings.py

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
...
MEDIA_DIR = os.path.join(BASE_DIR, 'media')
# Media
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
IMAGES_DIR = os.path.join(MEDIA_URL,"images")

python anywhere static files setup

I believe the error is due to the images_path method not retuning the correct location (but it works on localhost). Here is the model which stores the image and defines how images are saved: models.py

class Image(models.Model):

    # this might work?
    def images_path():
        return os.path.join(settings.IMAGES_DIR, 'usruploads')

    def resize(self):
        im = PIL.Image.open(self.image)
        size=(200,200)
        out = im.resize(size)
        out.save(self.image.__str__())

    def save(self, *args, **kwargs):
        super(Image, self).save(*args, **kwargs)
        self.resize()

    image      = models.ImageField(upload_to=images_path()[1:], max_length=255)

I will also throw in the media directory structure of the site in case this info is of use.

media directory 1 media directory 2

This is my first attempt at a deploying a Django web app via python anywhere so hopefully once this issue is fixed, it is a mistake I will never make again.


I have implemented the change you suggestd and the referenced url exists which is now a start however the server is claiming that it does not. I have printed out the URL and path of the image as follows: image paths I can go to the index page and enter this url and it loads the image.

Ok, your suggestion was correct uring path instead of __str__() worked. The reason the issue second issue was occurring was then due to the fact that I was opening the image using url and trying to save it using path it did not like this. Thanks for your help!

Upvotes: 0

Views: 656

Answers (1)

Victor
Victor

Reputation: 2919

Given

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
IMAGES_DIR = os.path.join(MEDIA_URL,"images")

and

class Image(models.Model):

    # this might work?
    def images_path():
        return os.path.join(settings.IMAGES_DIR, 'usruploads')

    def resize(self):
        im = PIL.Image.open(self.image)
        size=(200,200)
        out = im.resize(size)
        out.save(self.image.__str__())

    def save(self, *args, **kwargs):
        super(Image, self).save(*args, **kwargs)
        self.resize()

    image = models.ImageField(upload_to=images_path()[1:], max_length=255)

We can infer that

IMAGES_DIR = "/media/images"

and

image = models.ImageField(upload_to='media/images/usruploads', max_length=255)

That means files are uploaded to /<base_dir>/media/media/images/usruploads.

Issue

Looking at your logs, the error happens at the end of your logs.

    ...
    out.save(self.image.__str__())

The issue is self.image.__str__() returns the relative path/filename of the file, and when you pass a relative path to out.save , it will try to save that file in the provided path RELATIVE TO THE CURRENT WORKING DIRECTORY.

Solution

What you have to do instead (assuming you want to replace the original image) is pass the absolute path of the original image:

    ...
    out.save(self.image.path)

Upvotes: 1

Related Questions