This is the new project structure (from the Django 1.4 release notes).
myproject
|-- manage.py
|-- myproject
| |-- __init__.py
| |-- settings.py
| |-- urls.py
| `-- wsgi.py
`-- polls
|-- __init__.py
|-- models.py
|-- tests.py
`-- views.py
What I am not sure about is whether I should point STATIC_ROOT to
myproject/myproject/static/ (together with settings.py, urls.py...)
OR
The top-level directory myproject/static (next to myproject, myapp1, myapp2)?
STATIC_ROOT is not related to Python importing, so it totally depends on you. Normally, myproject/static/, thus os.path.join(PROJECT_ROOT, 'static/') in settings, is easier.
update as San4ez suggested, and notes inside settings.py
# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
Better to put static files of the poll app into poll/static/, according to your structure.
I agree with #okm that myproject/static/ is a good place for static, but also you can store images, css and js inside your app in myproject/polls/media. Than you have to configure django.contrib.staticfiles app and copy static from media to STATIC_ROOT with command
python manage.py collectstatic
The advantage of this approach that this allows you to spread your app with static and your app can be used freely in other projects
STATIC_ROOT is just a file path where the staticfiles contrib app will collect and deposit all static files. It is a location to collect items, that's all. The key thing is that this location is temporary storage and is used mainly when packaging your app for deployment.
The staticfiles app searches for items to collect from any directory called static in any apps that are listed in INSTALLED_APPS and in addition any extra file path locations listed in STATICFILES_DIRS.
For my projects I create a deploy directory in which I create a www folder that I use for static files, and various other files used only when deploying. This directory is at the top level of the project.
You can point the variable to any location to which your user has write permissions, it doesn't need to be in the project directory.
Related
My python backend server serves a react application as static files.
In react, everything inside the src directory is bundled when we build the app, however, there is one javascript file outside the src, in the public directory, that I left there because I want to be untouched after the build. the reason I did this, is because inside the src code, I create Workers, and to create workers we have to specify the url of the worker file. This file is called worker.js, it remains untouched after the build, but after deploying the backend, the frontend cannot access the /worker.js url because apparently django only serves static files, so /worker.js is not recognized and the index.html is returned instead. How can I make it possible to access this non-static js file?
Explanation of how static files work:
Development
Let's get this to work in a development situation first (django is serving your static files using runserver). STATIC_ROOT is not relevant in this case.
Django can find all your static files from these locations:
Any /static/ folder located inside your apps, e.g. if you have a blog app, then the folder /blog/static/ will be parsed.
Any folder specified in STATICFILES_DIRS, so for example if you have an assets folder in your main project, you'd add it to STATICFILES_DIRS with os.path.join(BASE_DIR, "assets") where BASE_DIR is the location of manage.py.
What if both the blog app and your assets directory need a "logo.png"? Instead of worrying that images, js files, css files have unique names, use namespacing. Inside the blog app, put all static files in /blog/static/blog/ so when using them you need to refer to /blog/logo.png and you know for sure it's going to be the right logo.png. Inside the main project, put the files in assets/assets (or call this static/assets instead) so you can refer to /assets/logo.png for the main assets of your project.
Now if you set STATIC_URL = "/static/", this tells django that all static files urls are prefixed with "/static/", i.e. the logo above can be retrieved with "/static/assets/logo.png" and "/static/blog/logo.png". This is required, since it allows to differentiate a url to a static file from urls that Django routes to views.
In practice, in your templates, you'll use {% static 'blog/logo.png' %} so you don't have to hard-code STATIC_URL everywhere.
Now enters webpack. It needs to put its packages assets in any of the above directories, or in its own directory that you **also add to STATICFILES_DIRS. Let's assume the latter: We also have a /webpack/webpack/ folder in our project that's defined in STATICFILES_DIRS, so all webpack assets will be accessed via the url prefix "/static/webpack/".
The worker.js file should be in "assets/assets" and inside your other scripts, if you refer to it via url (to fetch it with an HTTP request), you should refer to it via "/static/assets/worker.js" or using a relative url "../assets/worker.js".
Production
After you deploy, you don't serve your static files with Django anymore but with a webserver, e.g. Apache or nginx. You configure the web server to recognise any request starting with the STATIC_URL ("/static/") and fetch the corresponding file from STATIC_ROOT.
So the first thing to do is to copy all the static files of your django app into a folder/location that's reachable by your web server. That location is outside of your project folder.
Set STATIC_ROOT = os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(BASE_DIR)), 'static')), which points it to a "static" directory in the parent folder of your project.
Then run python manage.py collectstatic.
This will copy all static files into this new static folder outside of your project. You'll see:
path/to/dir/
|_ static/
| |_ blog/
| | |_ logo.png
| |_ assets/
| | |_ logo.png
| | |_ worker.js
| |_ webpack/
| |_ some_file.js
|_ django_project/
|_ manage.py
|_ main_app/
| |_ settings.py
|_ assets/
| |_ assets/
| |_ worker.js
|_ blog/
| |_ static/
| |_ blog/
...
Now when your web server sees the url "/static/assets/worker.js" it will return the file in "path/to/dir/static/assets/worker.js".
If you let your production server build the webpack files instead of committing them to your source (i.e. they are not inside "django_project"), then you should configure webpack to put them in the correct location "path/to/dir/static/webpack/" because that's where your web server will be looking for them.
Imagine now you move everything to a 3rd party storage provider. You then only have to do two things:
Install and configure the storage backend for that storage provider so that Django knows how to read/write files there (with collecstatic). This might include setting STATIC_ROOT, e.g. STATIC_ROOT = https://my-bucket.my-storage-provider.com/static.
Set STATIC_URL to the URL of the storage provider, e.g. STATIC_URL = https://my-bucket.some_cdn.com/. Here we point to the CDN which you've configured to know where to fetch the files from.
That's all, everything continues to work.
I had tried to setup static files in Django but failed.
I have the following directory structure
app
|
|- manage.py
|- requirements.txt
|- static
| |
| |- css
| |
| |- snapweb.css
|
|
}- templates
|- web
|
|- __init__.py
|- settings.py
|- urls.py
|- wsgi.py
/app/web/urls.py
from django.contrib import admin
from django.urls import path, include
from django.views.generic.base import TemplateView
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.conf import settings
import logging
urlpatterns = [
path('', TemplateView.as_view(template_name='home.html'), name='home'),
path('admin/', admin.site.urls),
path('accounts/', include('django.contrib.auth.urls')),
]
if settings.DEBUG:
urlpatterns += staticfiles_urlpatterns()
/app/web/settings.py
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
Take note that, I didn't run python manage.py collectstatic. As, if I want to run, I will get the following warning, which I have no idea how to solve it.
/app # python manage.py collectstatic
You have requested to collect static files at the destination
location as specified in your settings:
/app/static
This will overwrite existing files!
Are you sure you want to do this?
Type 'yes' to continue, or 'no' to cancel:
So, my problem is, I feel confused on my app behavior.
The following URL works. I didn't expect it to work, as I don't see /app/static/admin/css/base.css file exist. Where does Django pick up the file?
https://localhost:2053/static/admin/css/base.css
I also confused, for the following URL not working. Even though file /app/static/css/snapweb.css is there. Why Django doesn't pick up the file?
https://localhost:2053/static/css/snapweb.css
I wish both URLs, https://localhost:2053/static/admin/css/base.css and https://localhost:2053/static/css/snapweb.css will work. Is there any setup I had missed?
Also, how I can run python manage.py collectstatic successfully, without overwriting my /app/static?
First, you seem to be missing the django distinction between apps and the project (given you have named your project "app"). The project is what has manage.py and settings.py. The apps are what have models.py files.
Given you are using static files from the admin app as well as your own, you are going to need to do some restructuring. Django is looking for static files in STATIC_ROOT. In a "proper" setup, you're supposed to put static files in directories specific to your apps (as opposed to your project). The project static file (pointed to by STATIC_ROOT should have nothing you defined in it since that's where Django is going to put all your files when you run collectstatic.
Try moving your static folder to be a subdirectory of your app folder ("web/static") and running collectstatic.
See the docs for more info.
Preface this by saying I have now read multiple posts on this question (including here, here, and here). What I understand is that the static url in settings.py needs a modification for heroku to run these static files. What I need, explained like I am a child, is what tweak to make to these static url when the static directory is nested within the app -- as this was a best practice imparted in a recent tutorial (if this is not the ideal practice I would appreciate being corrected).
Question 1: Should the media files be kept in a directory within the app or at the project level?
Question 2: If the media files are kept within a directory inside the app, like my directory below, then how am I supposed to modify the url in settings.py to load the static files once pushed to heroku?
My project structure is the following:
gvlabs
__init__.py
__init__.pyc
settings.py
settings.pyc
urls.py
urls.pyc
wsgi.py
wsgi.pyc
manage.py
Procfile
requirements.txt
runtime.txt
welcome
__init__.py
__init__.pyc
admin.py
admin.pyc
apps.py
hello.py
migrations
models.py
models.pyc
static
css
fonts
images
js
templates
welcome
base.html
comingsoon.html
contact_us.html
index.html
post_list.html
tests.py
urls.py
urls.pyc
views.py
views.pyc
settings.py
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
PROJECT_DIR = os.path.join(PROJECT_ROOT,'../welcome')
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/
#STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_ROOT= os.path.join(PROJECT_DIR,'static')
STATIC_URL = '/welcome/static/'
# Extra places for collectstatic to find static files.
STATICFILES_DIRS = ()
# Simplified static file serving.
# https://warehouse.python.org/project/whitenoise/
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'
The main problem with your configuration is the STATIC_ROOT setting. You should change this to something like os.path.join(BASE_DIR, 'static_root').
STATIC_ROOT should point to an empty directory (it doesn't need to exist, Django will create it if necessary) where Django can collect your static files together and do any necessary processing on them before it serves them. It is not the directory where you store your static files.
Regardless of where you put your static files, you shouldn't need to change the STATIC_URL setting. Just leave it as /static/. The main reason for needing to change this is when you're serving static files via a CDN, when it would be set to something like https://my-cdn.example.com/static/
I would keep static files in a directory at the project level. Sometimes, when creating a reusable app it makes sense to bundle everything together by storing its static files in a directory within the app. But most projects I've worked on have kept the main set of static files at the project level.
It doesn't really matter where you put your static files as long as you tell Django where to find them. You do this by adding the path to the directory to the STATICFILES_DIRS setting like so:
STATICFILES_DIRS = [
os.path.join(PROJECT_DIR, 'static'),
]
(Technically, if your static files are in an app directory Django should be able to find them automatically, but let's keep things simple and explicit.)
As a side note: be careful not to use the term "media" here as that has a specific meaning in Django terminology where it refers to user-uploaded files like profile images rather than files that belong with your codebase like CSS and JavaScript files.
My project structure
|- myProject
|- manage.py
|- myProject
|- settings.py
|- static // This is my STATIC_ROOT
|- myApp
|- static // This is where I edit and save my static files
So I run the collectstatic command. My css/js files are gathered (and compressed into a single file) into the STATIC_ROOT directory (myProject/myProject/static). So far so good.
First question: How do I serve them?
I tried calling http://127.0.0.1:8000/static/css/styles.css but it returns a 404 file not found error.
I tried adding STATIC_ROOT in the STATICFILES_DIRS but then I get the error:
The STATICFILES_DIRS setting should not contain the STATIC_ROOT
setting.
Second question: Can Django serve "project-wide" static files?
I know that you can serve "application-wide" static files by calling "/static/myApp/my-static-file.css".
But does Django know about myProject/myProject/static the way it knows about the static folder inside each app? Or is it something you need to tell explicitly?
I've read some blog/forum posts saying that you need to change urls.py to but I tried, without success. Do I have to?
I find it pretty hard to find information about static files in Django's documentation and I'm very confused right now.
EDIT: now I am really confused: I tried setting PIPELINE_ENABLED = False and now this url works. http://127.0.0.1:8000/static/css/styles.css but it doesn't help because when PIPElINE_ENABLED is False, it doesn't try to call the compressed css, but all files separately.
I needed to set DEBUG = True and PRODUCTION = False to get it to serve static files. Just the DEBUG = True would not do it.
I want to be able to load my static files on my local server, but when I request them, the browser returns 404 for every resource.
From what I can understand, STATIC_URL is the url in which my static files will be served. And STATICFILES_FINDERS specifies how my static files will be discovered. I set STATICFILES_DIRS to search for the static directory at the project root, but it doesn't seem to be be finding it.
On my settings.py,
# Python 2.7.5, Django 1.6
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
STATIC_URL = '/static/'
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)
STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)
This is my directory structure:
.
|-- myapp
|-- settings.py
|-- ...
static
|-- images
|-- javascript
|-- stylesheets
Here are a couple of ideas:
You need a server for your static files. Are you using Apache HTTP server? The easiest way to serve your static files is to alias them in the httpd.conf file:
Alias /static/ /path/to/static/
<Directory /path/to/static>
Require all granted
</Directory>
You need to specify a STATIC_ROOT, which could be /path/to/your_project/static but then you probably want to put your current static files and folders somewhere else, because everything in STATIC_ROOT will be overwritten when you call manage.py collectstatic. I put all of my static files, such as Bootstrap, Tablesorter, images and icons in a folder called assets, then put assets in my STATICFILES_DIR list.
Use manage.py collectstatic to collect all static files and put them in STATIC_ROOT so that Apache can find them. Static files for the admin site will be automatically copied even if you do not add them to the list of STATICFILES_DIR.
Check out this post I wrote, which has several links to Django documentation on the topic.