djangodjango-imagekit

Django admin uploaded image in production


The images i upload through the admin-interface i production cannot be found, though it exists on the server.It loads fine in development. I use Django Image-kit to resize the uploaded image.

The image isn't displayed on the website and if i follow the image url, I get

<h1>Not Found</h1>
<p>The requested URL /media/CACHE/images/references/<reference-name>/<image-name>/211b0022f8a2baad7cdc527711dcb.jpg was not found on this server.</p>

The uploaded image is not added to my static files, which are correctly displayed.

My model looks like this:

def generate_unique_slug(instance, field):
    original = slugify(field)
    unique = original
    numb = 1
    while instance.objects.filter(slug=unique).exists():
        unique = f'{original}-{numb}'
        numb += 1
    return unique

def reference_main_image_path(instance, filename):
    sub_folder = instance.slug
    return f'references/{sub_folder}/{filename}'

class Reference(models.Model):
    title = models.CharField(max_length=60)
    description = models.TextField(max_length=2000)
    slug = models.SlugField(max_length=12, unique=True, blank=True)
    main_image = models.ImageField(
        upload_to=reference_main_image_path, default='default.png')
    main_thumbnail = ImageSpecField(source='main_image',
                                processors=[ResizeToFill(540, 300)],
                                format='JPEG',
                                options={'quality': 80},)
    tags = TaggableManager()

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        if self.slug:
            if slugify(self.title) != self.slug:
                self.slug = generate_unique_slug(Reference, self.title)
        else:
            self.slug = generate_unique_slug(Reference, self.title)
        super().save(*args, **kwargs)

My view.py:

def reference(request):
    context = {
        'references': Reference.objects.all(),
    }
    return render(request, 'home/references.html', context)

In the ´html` code I 'call' the image like this:

<img src="{{ reference.main_thumbnail.url }}"> 

My settings.py static and media variables look like this:

STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/'

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

I've run manage.py collectstatic

Should my upload_to in the be changed? Or how do I tell Django to look in the folder when 'collecting static' and then change the html to look in the static folder?

It seems weird to me that the documentation of image-kit should only regard 'development' or am I missing something?

Thank you!

Edit: I'm using gunicorn and Nginx in production, but as stated, my static files er loaded just fine.

Edit 2: Nginx conf:

server {
    server_name <server_names>;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/<user>/projects/<project>/<project>;
    }

    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;
    }
}

I left out some certbot SSL configuration.

Edit 3:urls.py:

from django.urls import path
from . import views
from django.conf.urls.static import static
from django.conf import settings


urlpatterns = [
    path('', views.home, name='home'),
    path('ydelser/', views.service, name='service'),
    path('referencer/', views.reference, name='reference'),
    path('kontakt/', views.contact, name='contact'),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Solution

  • To serve media files with nginx you should add appropriate location similarly to static:

    location /static/ {
        root /home/<user>/projects/<project>/<project>;
    }
    
    location /media/ {
        root /home/<user>/projects/<project>/<project>;
    }
    

    just like you did it in django:

    ...
    STATIC_URL = '/static/'
    ...
    MEDIA_URL = '/media/'
    

    However, if you don't want to serve media files with nginx (which is recommended) and still want to server them with django (which is not recommended) then make sure that line

    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    

    is enabled when DEBUG=False.

    Note, you shouldn't treat media files as static - they are logically different. Whilst static files belong to and are shipped with your solution/project, media files are not part of your project and usually are produced by users.

    ps

    if you've uploaded some files into your website locally, then they are located accordingly to this:

    def reference_main_image_path(instance, filename):
        sub_folder = instance.slug
        return f'references/{sub_folder}/{filename}'
    
    class Reference(models.Model):
        ...
        main_image = models.ImageField(
            upload_to=reference_main_image_path, default='default.png')
    

    If you did not copy them (files located on hard drive within folder configured above) to prod server - they will not show up. Copy them manually if needed and match destination folder with nginx location.