Struggling with file upload and serving in production

I have setup my python project using nginx and gunicorn as described in this tutorial

so far everything works perfectly fine. My project is in /root/project_folder/

I want to upload files via the admin page, but I get a bad request error 400. The media folder I want to add the files to is /var/www/my_domain/media (owned by the group www-data). This is also properly configured since I can see the images when I move them manually into that folder.

Do you guys maybe have any idea why the issue may be ?

the main problem is when uploading I need to save the image to the media root:


But when I send request to view the image the web server returns the following:


The upload_to path needs to be images/dad/ProfilePicture/offline_screen.png for correct request but then the image is uploaded to the wrong folder

Any ideas ? Thanks in advance!


Here is my nginx config `

server {
    server_name ip_address;

location = /favicon.ico { access_log off; log_not_found off; }
location  /static/ {
    root /var/www/domain;

location = /media/ {
    root /var/www/domain;

location / {
    include proxy_params;
    proxy_pass http://unix:/var/log/gunicorn/domain.sock;

listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/domain/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/domain/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

server {

if ($host = www.domain) {
    return 301 https://$host$request_uri;
} # managed by Certbot

if ($host = domain) {
    return 301 https://$host$request_uri;
} # managed by Certbot

listen 80;
server_name domain www.domain ip_address;
return 404; # managed by Certbot


Here is my media root / media url:

MEDIA_ROOT = '/var/www/domain/media' #os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'


urlpatterns = [
path('', include('webpages.urls')),

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
    urlpatterns += static(settings.STATIC_URL,document_root=settings.STATIC_ROOT)

And finally how I serve and upload Images:

def get_path_of_content_image(instance, filename):
    return os.path.join(settings.MEDIA_ROOT, "images", str(instance.course.topic), str(instance.course), filename)

class Topic(models.Model):
title = models.CharField(max_length=100)
description = models.TextField(max_length=445)
image = models.ImageField(upload_to=get_topic_profile_path, default="images/default.jpeg")

def __str__(self):
    return self.title

def image_tag(self):
    if self.image:
        return mark_safe('<img src="%s" style="width: 200px; height:200px;" />' % self.image.get_image())

def get_image(self):
    if self.image:
        return str(self.image.url).replace('/media/var/www/domain', '')  ########1
        return settings.STATIC_ROOT + 'webpages/img/default.jpeg'

image_tag.short_description = 'Current Image'

I wrote this line #######1 since set the upload path to the full media root but then in order to return the correct path I need to remove the media root prefix. And also very importantly this only works if DEBUg set to TRUE.

The path being stored in Topic.image is the relative path that gets appended to MEDIA_ROOT in the filesystem. Then when creating the urls, it assumes that component that serves the media files will also be serving files from that MEDIA_ROOT directory and only needs the relative path stored in Topic.image.

The code version of this answer is to remove settings.MEDIA_ROOT from your upload_to function.

def get_path_of_content_image(instance, filename):
    return os.path.join("images", str(instance.course.topic), str(instance.course), filename)
1 Like