Django | joined path is located outside of the base path component {% static img.thumbnail.url %}, Error 400 with whitenoise
Asked Answered
S

4

13

I've finish my first app in Django and works perfectly, but still have pre-deployment problems since I set DEGUG=False ... Here is just to display an image in a template... T_T

I was using this, but now it does'nt work when I use whitenoise to serve my image localy... And it return a Bad Request(400) error...

Models.py

class GalleryItem(models.Model):
    thumbnail = models.ImageField(blank=True,upload_to='gallery/thumb')
    img_wide = models.ImageField(blank=True,upload_to='gallery')

template.py

{% load staticfiles %}
{% for img in img_to_display %}
    <a href="{{ img.img_wide.url}}" class="swipebox" title="">
        <img src="{% static img.thumbnail.url %}" alt="{{ img.alt}}">
    </a>
{% endfor %}

urls.py

from django.conf.urls import url, include
from django.contrib import admin
from django.conf import settings
import os

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

urlpatterns = [
    url(r'^gallery/', include('gallery.urls')),
    url(r'^shop/', include('shop.urls')),
    url(r'^events/', include('events.urls')),
    url(r'^page/', include('paginator.urls')),
    url(r'^news/', include('blog.urls')),
    url(r'^ckeditor/', include('ckeditor_uploader.urls')),
    url(r'^admin/', admin.site.urls),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

settings.py

import os
import dj_database_url

BASE_DIR = os.path.dirname(os.path.dirname(__file__))
print("BASE_DIR = ",BASE_DIR)
MEDIA_ROOT = os.path.join(BASE_DIR, 'wt/static/media/')
MEDIA_URL = '/media/'

SECRET_KEY = 'SECRET_KEY'

DEBUG = False

INSTALLED_APPS = [
    'ckeditor',
    'ckeditor_uploader',
    'team.apps.TeamConfig',
    'gallery.apps.GalleryConfig',
    'shop.apps.ShopConfig',
    'events.apps.EventsConfig',
    'blog.apps.BlogConfig',
    'paginator.apps.paginatorConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
]

ROOT_URLCONF = 'wt.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                "django.contrib.auth.context_processors.auth",
                "django.core.context_processors.request",
                "django.core.context_processors.debug",
                "django.core.context_processors.i18n",
                "django.core.context_processors.media",
                "django.core.context_processors.static",
                "django.core.context_processors.tz",
                "django.contrib.messages.context_processors.messages",
            ],
        },
    },
]

WSGI_APPLICATION = 'wt.wsgi.application'

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'wt_db',
        'USER': 'postgres',
        'PASSWORD': 'PASSWORD',
        'HOST': '127.0.0.1',
        'PORT': '5432',
    }
}


AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

LANGUAGE_CODE = 'fr-fr'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True

db_from_env = dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(db_from_env)


ALLOWED_HOSTS = ['localhost', '127.0.0.1',]

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

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'wt/static'),
    os.path.join(BASE_DIR, 'wt/staticfiles'),
]

STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'

CKEDITOR_UPLOAD_PATH = 'uploads'
CKEDITOR_IMAGE_BACKEND = 'pillow'
CKEDITOR_BROWSE_SHOW_DIRS = True

Here my error log :

The joined path (E:\media\gallery\thumb\lost-thumb.jpg) is located outside of the base path component (E:\dev\wt\wt\wt\staticfiles)
[15/May/2016 20:01:41] "GET /page/gallery HTTP/1.1" 400 26

Thanks a lot for helping ! :)

EDIT :

principal structure

project folder

Starlet answered 15/5, 2016 at 18:9 Comment(4)
Looks like you are missing something with your project structure. Please also add your project folder tree. If you are on Windows, from command line, navigate to your project folder and run tree /F /A. If you are on linux just run tree.Neoplatonism
Thanks for your help Alix ! I've updated the post, (too big output with tree cmd, so I just add screenshots at the end). You have to click on the links because I don't have 10 reputation points to display it... T_T Thanks again !Starlet
With a little research, i can tell this is related with Windows environment. Since i don't have Windows installed i can't say more. Sorry. If you can't find a solution, try to install a ubuntu into VirtualBox and set build your project in ubuntu. You can google joined path is located outside of the base path component for more details.Neoplatonism
Thanks, I'm searching on that nowStarlet
S
2

I guess it was a security issue. Even if "whitenoise" is good to serve true static files in production, it can't serve media files.

I was making a structure error :

# Don't place your 'media' files IN your 'static' file like this :

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

MEDIA_ROOT never have to be in the "static" file of your project (even if you can make it works in some ways, it's not a good practice I think).

'MEDIA' files (in production), have to serve out of the Django project. I've read somewhere that we have to use a CDN. And firstly I choose CloudFlare (because it's free), but it wasn't working, cause you need a subdomain/hostname to point your MEDIA_ROOT, and Cloudflare doesn't give that. Finally, I choose Amazon S3.

So, in conclusion, write something like {% static img.thumbnail.url %} makes no sense. Because everything uploaded via admin/user haven't to be in "static".

Use {{ img.thumbnail.url }} instead.

Starlet answered 19/5, 2016 at 11:45 Comment(1)
You are right, media and static files is different things, they should be seperated, and django not work well serveing images (They say that), so is better use some external server to process that one, i like to use NGinX and GUnicorn to configure and serve my server and static filesGlorify
D
7

Bro, you cant load staticfile when you use images on models, there is 2 different ways to work with images in django.

Statics files is for files that are static(images files like logo of your company, banners, javascript files, css files)

Media Files is for dinamic files like user photo, user gallery, product images

  1. Static Files - This way you use your staticfiles save at your static folder where you place it in static root at your settings.py and then you use {% load staticfiles %} and {% static '' %}
  2. Media Files - This files is that one you save with your models, ImageField, FileField and etc... that one you do not load as static, cuz they are not a static file (you can edit it from your models), that do not means you will save it on your database, this will generate a copy of your file with hashed name on it at you media folder where you place it in media root at your settings.py and media files you use like that {{ ..url }} so in your case gallery.thumbnail.url (btw, remind to call your gallery object at your views and send it to template to allow your to use it)

So the other anwers was right, you need to decide what you want to use, keep in mind that your path localy is different where you deploy, remember to use environment variables with the right path to set up in your settings

Django Docs: https://docs.djangoproject.com/en/1.11/topics/files/

Direct answered 20/6, 2017 at 19:10 Comment(2)
The problem with Django's line of thinking on this is that a default image for a field is a static file provided by the developer and deployed with the software, not a user upload. ImageField should allow defaults to be set from /static/Catamaran
Sorry only saw your answer now, usualy when i provide some default picture, or i dont register it on my database and load one default from statis file (like 'user_default.mpeg') or i (rarely) bind the image with my objectGlorify
S
2

I guess it was a security issue. Even if "whitenoise" is good to serve true static files in production, it can't serve media files.

I was making a structure error :

# Don't place your 'media' files IN your 'static' file like this :

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

MEDIA_ROOT never have to be in the "static" file of your project (even if you can make it works in some ways, it's not a good practice I think).

'MEDIA' files (in production), have to serve out of the Django project. I've read somewhere that we have to use a CDN. And firstly I choose CloudFlare (because it's free), but it wasn't working, cause you need a subdomain/hostname to point your MEDIA_ROOT, and Cloudflare doesn't give that. Finally, I choose Amazon S3.

So, in conclusion, write something like {% static img.thumbnail.url %} makes no sense. Because everything uploaded via admin/user haven't to be in "static".

Use {{ img.thumbnail.url }} instead.

Starlet answered 19/5, 2016 at 11:45 Comment(1)
You are right, media and static files is different things, they should be seperated, and django not work well serveing images (They say that), so is better use some external server to process that one, i like to use NGinX and GUnicorn to configure and serve my server and static filesGlorify
R
0

paste the below code in settings.py file

STATIC_URL = '/static/'

# Add these new lines
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

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

and in urls.py

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

if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL, document_root = settings.STATIC_ROOT)
    urlpatterns += static(settings.MEDIA_URL, document_root = settings.MEDIA_ROOT)
Ruyter answered 1/12, 2022 at 6:28 Comment(0)
S
-1

Try <img src="{{ img.thumbnail.image.url }}" alt="{{ img.alt}}">

Switzerland answered 16/5, 2016 at 9:31 Comment(2)
Thanks for helping ! But no, by this way, Django doesn't use "static", and because I'm on DEBUG=False, it doesn't serve my images... But yes, with that I don't have the 400 error. Just a 404 for the img : <img src="/media/gallery/thumb/my_img_wpNljpN.jpg" alt="img_alt"> My problem is that I can't have the right first part of the url, because 'static' seems really want a true name of a file (like {% static 'path/to/my_img.jpg' %}, not a variable (like {% static img.thumbnail.url %} )....Starlet
I have finaly solve my problem, and you where right in some ways. :)Starlet

© 2022 - 2025 — McMap. All rights reserved.