Where to put templates and static assets for deployment - django

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

Related

Why Django can't find static folder in BASE_DIR?

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

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 Pycharm 2020.2.2 not resolving static files when using "pathlib.Path" to address BASE_DIR

I'm using the latest version of Pycharm, 2020.2.2 and django 3.1.
In my project, I removed the default settings.py and created a directory named settings, so the whole project root looks like:
tsetmc
├── asgi.py
├── celery.py
├── context_processors.py
├── __init__.py
├── settings
│   ├── base.py
│   ├── __init__.py
│   ├── local.py
├── urls.py
├── views.py
└── wsgi.py
and in the base.py, I defined the static files setting as:
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent.parent
...
STATIC_URL = '/static/'
STATICFILES_DIRS = [
BASE_DIR / 'assets/'
]
STATIC_ROOT = BASE_DIR / 'staticfiles/'
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media/'
Everything works fine in the browser and the static files are successfully loaded using the {% static %} tag; However, Pycharm can not resolve any of the static files in the templates.
I enabled Django Support, set Django project root and settings in the Pycharm settings accordingly and also set the Template Language as Django; but it didn't solve the issue.
After some trial-and-error, I found an odd solution; If I use import os and os.path.join() to locate the static paths, instead of from pathlib import Path and /, Pycharm can resolve the static files without any problem.
So when I changed my base.py to look like this:
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'assets')
]
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles/')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
(after invalidating the cache, without changing any other configuration)
Pycahrm can fully resolve the static files.
What am I missing here? Is there any problem with using Path to address the static files? or the problem is about the Pycharm itself?
Thanks for the help.
This is a known limitation of PyCharm, you can see this 6 years old bug report: https://youtrack.jetbrains.com/issue/PY-13911. Other users have the same problem, for example here: https://youtrack.jetbrains.com/issue/PY-45244.
This is the recommended solution:
Please consider using os.path for BASE_DIR. (...)
I use https://github.com/pydanny/cookiecutter-django for my projects, which uses pathlib in settings. Even the official Django documentation uses pathlib.
That's why I use this hack in settings so that PyCharm can autocomplete and I can use pathlib:
import os
from pathlib import Path
ROOT_DIR = Path(__file__).resolve(strict=True).parent.parent.parent
# my_project/
APPS_DIR = ROOT_DIR / "my_project"
# STATIC
# ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#static-root
STATIC_ROOT = str(ROOT_DIR / "staticfiles")
# https://docs.djangoproject.com/en/dev/ref/settings/#static-url
STATIC_URL = "/static/"
# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
STATICFILES_DIRS = [
str(APPS_DIR / "static"),
os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), 'my_project', 'static')
]

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.

Media files are served, static files aren't

I'm stuck due to an evergreen issue, static files not served. Conversely the files placed in the MEDIA_ROOT subtree get served correctly under MEDIA_URL.
Stripped settings.py:
DEBUG = True
STATIC_URL = '/static/'
STATIC_ROOT = '/home/foo/devel/static'
MEDIA_URL = '/media/'
MEDIA_ROOT = '/home/foo/devel/media'
# the following is deprecated but is it seems grappelly requires it
ADMIN_MEDIA_PREFIX = STATIC_URL + "grappelli/"
STATIC_FILES = ()
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)
To create the project I did:
$ cd /home/foo/devel/
$ virtualenv testdrive
$ . bin/activate; pip install django; cd testdrive
$ django-admin.py fbtest
and got this directory tree (stripped):
. <-- /home/foo/devel/
├── bin
├── fbtest
│   └── fbtest
│   ├── media
│   │   └── foo.jpg
│   ├── static
│ └────── foo.jpg
├── include
└── lib
Files under STATIC_URL should be served automatically by Django staticfiles (not in my case), while other files have to be handled manually. So I appended these lines to urls.py:
import settings
if settings.DEBUG:
urlpatterns += patterns('',
url(r'^%s(?P<path>.*)$' % settings.MEDIA_URL.lstrip("/"),
'django.views.static.serve', {
'document_root': settings.MEDIA_ROOT,
}),
)
Accessing http://host/media/filebrowser/foo.jpg works, while http://host/static/foo.jpg gives error 404. Why?
Files under STATIC_URL should be served automatically by Django staticfiles (not in my case), while other files have to be handled manually.
That's incorrect. Django never serves STATIC_ROOT ever -- not even in development. What it does do is make files in each app's "static" directory and files in any directory specified in STATICFILES_DIRS available at STATIC_URL. You don't actually manually put anything in STATIC_ROOT ever; in fact, in development, you shouldn't even have the directory there. Put simply, STATIC_ROOT is only a dumping ground for your static files in production when you run the collectstatic management command.
In development, all static files should go into someapp/static, where "someapp" is the app they apply to. In the case that the files apply to the project as a whole, a global CSS file for example, you need to create an entirely different directory (i.e. not the same as STATIC_ROOT or MEDIA_ROOT) and then add that directory to STATICFILES_DIRS. For example, I normally call mine "assets", so:
STATICFILES_DIRS = (
os.path.join(os.path.dirname(__file__), 'assets'),
)
It was a silly error. I forgot to add fbtest to INSTALLED_APPS, so the static file machinery didn't manage static files for this app.
This problem is realy evergreen...
Some hints:
TEMPLATE_CONTEXT_PROCESSORS = (
# ...
'django.core.context_processors.static',
# ...
)
INSTALLED_APPS = (
# ...
'django.contrib.staticfiles',
# ...
)
Did you use? django-admin-collectstatic command?
Can you help add show_indexes=True in url settings?
Some symbolic link?
Run app with --adminmedia=../grappelli/static/grappelli arg.?
My settings for django 1.4 (no grappelli):
urls.py
if settings.DEBUG:
urlpatterns = patterns('',
url(r'^%s(?P<path>.*)$' % settings.STATIC_URL.lstrip('/'), 'django.views.static.serve',
{'document_root': settings.STATIC_ROOT, "show_indexes": True}),
url(r'^%s(?P<path>.*)$' % settings.MEDIA_URL.lstrip('/'), 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, "show_indexes": True}),
) + urlpatterns
settings.py
MEDIA_ROOT = os.path.join(PROJECT_DIR, 'media')
STATIC_ROOT = os.path.join(PROJECT_DIR, 'static')
MEDIA_URL = '/media/'
STATIC_URL = '/static/'
ADMIN_MEDIA_PREFIX = '/static/admin/'
TEMPLATE_CONTEXT_PROCESSORS = (
# ...
'django.core.context_processors.static',
# ...
)
INSTALLED_APPS = (
# ...
# 'django.contrib.staticfiles',
# ...
)