Why Django can't find static folder in BASE_DIR? - django

I have these directories:
└── MY_FOLDER
├── MY_PROJECT
│   └── settings.py
│     
├── MY_APP
├── STATIC
│   └── style.css
├── MEDIA
└── manage.py
In the settings.py I've indicated:
BASE_DIR = Path(__file__).resolve().parent.parent
STATIC_URL = 'static/'
STATICFILES_DIR = (os.path.join(BASE_DIR,'static'))
When I
print(STATICFILES_DIR)
I get a path:
MY_FOLDER/STATIC - what is exactly I wanted.
But Django don't see any css there, in that folder.
I tried to put my css to MY_APP/STATIC and it started to work correctly. But I want to have it not in MY_APP but in BASE_DIR/STATIC. How to do it?
Or if it is impossible, how to make a correct path for STATICFILES_DIR to let it search my statics in all apps I'll add in the future. Not only in one app by doing this:
STATICFILES_DIR = (os.path.join(BASE_DIR,'MY_APP','static'))
Thanks.

Always look for the documentation, you are naming the directive wrong and it also should be a list.
STATICFILES_DIRS = [
BASE_DIR / "static",
]

Try this:
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
Note: your static folder must be lowercase and ensure that static folder must be inside project root not inside an app

Related

Is there a better way to load Django static directories for multiple apps than this? Thank you

I currently have the following in settings.py:
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
#add app-specific static directory
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'project/static'),
os.path.join(BASE_DIR, 'project/apps/blog/static/'),
os.path.join(BASE_DIR, 'project/apps/users/static/'),
os.path.join(BASE_DIR, 'project/apps/comments/static/'),
os.path.join(BASE_DIR, 'project/apps/categories/static/'),
)
Should I be doing this in one line? Thanks very much.
You can add custom static file finder that would sort you out, but generally if you have /static folder inside of the app it should be discovered by
django.contrib.staticfiles.finders.AppDirectoriesFinder
as documented
The default will find files stored in the STATICFILES_DIRS setting
(using django.contrib.staticfiles.finders.FileSystemFinder) and in a
static subdirectory of each app (using
django.contrib.staticfiles.finders.AppDirectoriesFinder). If multiple
files with the same name are present, the first file that is found will be
used
Source
A better practice is to put all your static files in the same folder in your root directory instead of each app:
# ...
├── app1
├── app2
├── project
├── manage.py
├── media
├── requirements.txt
├── static
│ ├── css
│ ├── icons
│ ├── img
│ ├── js
│ └── vendor
Then in your settings.py assign this variable:
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ]
staticfiles_dirs sets the directory and tells Django where to look up for your static files, in this example, our folder is named 'static' in our root directory, os.path.join will join the base directory(root) with static.
BTW STATIC_ROOT is usually used in a production environment, when you run 'collectstatic` command, all static files including your 3rd party apps will be copied to this 'staticfiles' folder.
Also, you can put templates of each app into the same folder in a similar way:
# root
└── templates
├── app1
├── app2
├── app3
├── base.html
└── index.html
And in your settings.py, add the directory of 'templates' folder.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': { # ...
],
},
},
]
Personally, I think this would be much cleaner.
You can reference my project for the file structure:
here

Django not serving static files while STATIC_ROOT configured

I have a cloned project and I need to serve the static files with Django itself. It is my first time serving static files this way (in the past I used Nginx/Apache to serving media and static files). here is my try to serve static files by Django itself in production:
1- Adding STATIC_URL and STATIC_ROOT to settings.py:
...
STATIC_URL = '/static/'
STATIC_ROOT = os.environ.get('DH_STATIC_ROOT_DIR', os.path.join(BASE_DIR, 'static/'))
2- project's directory tree:
├── my_project
│   ├── DH
│   ├── env
│   ├── apps
│   ├── manage.py
│   ├── README.md
│   ├── requirements.txt
│   ├── static
│   └── templates
3- running ./manage.py collectstatic and working well. here is static/ directory's tree after this command (from past some static file exists in static directory because this project is MVT and loading templates):
├── admin
├── css
├── fonts
├── js
├── media
└── plugins
4- let Django serve static in production( in urls.py):
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('', index, name='index'),
path('admin/', admin.site.urls)
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
5- how html templates reference to static files:
{% load static %}
...
<link href="{% static 'plugins/global/plugins.bundle.css' %}" rel="stylesheet" type="text/css" />
For example, in Chrome (inspect) I can see the template page request to http://127.0.0.1:8000/static/media/logos/logo-6.png that static/media/logos/logo-6.png exist (all request to static files raise 404 HTTP status code). with this configuration not working even in DEBUG=True what I am doing wrong? Thank you in advance.
As documentation states, serve not suppose to be used in production. If you don't want to use nginx or apache, then consider using whitenoise. All you need to do is install it by pip install whitenoise and add these lines to middleware:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
# ...
]

Django global static files not loading

I want to have global static files and templates for all my apps. My apps also will have templates and static files It will look something like this:
I am loading my global files like these but it is not working.
{% load staticfiles %}
href="{% static 'bootstrap/css/bootstrap.min.css' %}"
and I get:
"NetworkError: 500 Internal Server Error - http://localhost:8000/static/bootstrap/css/bootstrap.min.css"
By the way I can access to my apps static but not the global, I debug the STATIC_ROOT and PROJECT_ROOT and they seem good.
PROJECT_ROOT ='C:\\webpages\\client_portal\\client_portal'
projectname]/ <- project root
├── [projectname]/ <- Django root
│ ├── __init__.py
│ ├── settings/
│ ├── urls.py
│ └── wsgi.py
├── apps/
│ └── __init__.py
│
├── manage.py
│
├── static/
│ └── GLOBAL STATIC FILES
└── templates/
└── GLOBAL TEMPLATES
My settings.py looks like this:
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = os.path.join(PROJECT_ROOT, '/static')
STATIC_URL = '/static/'
# Extra places for collectstatic to find static files.
STATICFILES_DIRS = (
os.path.join(PROJECT_ROOT, '/static'),
)
STATIC_ROOT and STATICFILES_DIRS should not be the same. Create a different directory, eg staticfiles, to store your development static files and use that in STATICFILES_DIRS instead.
I think your problem is that you have an unneeded forward slash in STATICFILES_DIRS. So change this:
STATICFILES_DIRS = (
os.path.join(PROJECT_ROOT, '/static'),
)
to this:
STATICFILES_DIRS = (
os.path.join(PROJECT_ROOT, 'static'),
)
Hope it helps, it worked for me in Django 2.0, without the need of using PROJECT_ROOT neither STATIC_ROOT.

Where to put templates and static assets for deployment

Where should I put all my static assets for deployment? Currently I have this in my settings.py
if DEBUG:
MEDIA_URL = '/media/'
STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static", "static_only")
MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static", "media")
STATICFILES_DIRS = (
os.path.join(os.path.dirname(BASE_DIR), "static", "static"),
)
Here's my directory structure on my local machine:
├── env
├── src
| ├── esp_project
| ├── reports
| └── templates
| ├── registration
| └── reports
└── static
└── static
└── css
├── js
└── img
From the docs I understand they should be served by apache2, not by python. Could someone clarify this? And what about templates, are those in the "right" place?
For your templates you can make a new folder in you main static directory.
In your settings.py you can set the path like this.
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), 'static', 'templates'),
)
You can also add in template loaders to your settings.py.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
Now Django will look in static/static/templates for your templates (which are static files).
The rest looks good just make sure you have STATIC_URL = '/static/' above if Debug:
See: Django Project Loading Templates

Django.staticfiles doesn't collect admin files

I noticed that staticfiles doesn't copy the admin's static files to STATIC_ROOT. I was under the impression (and I can't find references for that just now) that once you include django.contrib.staticfiles to your INSTALLED_APPS, it would automatically copy admin's static files (as well as all the other ones). However, it doesn't seem to be the case.
From browsing a dozen related questions on SO it seems that the accepted way is to include the hardcoded path to your virtualenv'd admin path to your NGINX, such as here:
location /static/admin {
root /webapps/hello_django/lib/python2.7/site-packages/django/contrib/admin/;
}
However, this seems rather dirty to me.
I should also mention that finders are working for me, i.e.
$ ./manage.py findstatic admin
Found 'admin' here:
/<path to venv>/lib/python2.7/site-packages/django/contrib/admin/static/admin
Am I missing something here?
Check if you have all settings set like that in your settings.py.
I suppose that your static files are under static dir in your project root folder.
import os
import sys
STATIC_ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static/')
STATIC_URL = '/static/'
ADMIN_MEDIA_PREFIX = '/static/admin/'
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)
INSTALLED_APPS = (
# default apps
'django.contrib.staticfiles',
# etc
)
STATICFILES_DIRS = ()
nginx config:
location /static {
alias /path_to_your_project/static;
access_log off;
expires max;
}
Turns out there was a subtle problem with my settings.py splitting method. For anyone coming here from Google, I was following deploydjango.com's and strategy on splitting settings.py, however ROOT_DIR was being defined in terms of the project, i.e. the following structure
$ tree -L 2
.
├── static
├── apps
└── project
├── __init__.py
├── settings
│   ├── __init__.py
│   ├── base.py
│   ├── dev.py
│   └── prod.py
├── urls.py
└── wsgi.py
with the following setting
STATICFILES_DIRS = (
ABS_PATH('apps', 'example_app', 'static'),
)
would result in ROOT_DIR being set to project/. And since ABS_PATH function defines paths based on ROOT_DIR, the apps/ folder is not visible (it should be preceded with '..').
The solution is of course to move apps/ folder inside the project/ folder, which makes sense. I.e. the correct structure is as follows:
$ tree -L 2
.
├── static
└── project_name
├── __init__.py
├── apps # <-- apps moved here
│   └── example_app
├── settings
│   ├── __init__.py
│   ├── base.py
│   ├── dev.py
│   └── prod.py
├── urls.py
└── wsgi.py
I realised this problem is very tied to the way I was doing things, however since this structure can be seen by some people as "best practice" (although some disagree), I hope this helps someone!