how to make django serve non static js files? - python

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.

Related

connecting multiple create-react-apps with django

I have one big Django project consisting out of several small apps, independent from each other but partly sharing the same database or/and models.
All the apps are created with python manage.py startapp myappa so they have their own urls.py and views.py.
I started using create-react-app for the front end for two of those apps and connected them successfully by turning the index.html of the react project into a template and serve it through the views.py (more here).
Now each one of these create-react-app projects has its own build folder which's path I include in the STATICFILES_DIRS in settings.py to collect the static files.
It looks like this:
static/
templates/
myappa/
build/
static/
index.html
...
myappb/
build/
static/
index.html
...
Now, I was wondering if there is a way to have only one build folder that contains all built files respectively to their projects something like:
myappa/
myappb/
static/
templates/
build/
myappa/
static/
index.html
...
myappb/
static/
index.html
...
I'm imagining that this folder would live on the same level as the the static folder and the appa and appb folders.
One way, since by default I can't have the build folder outside the project folder structure(?) and I don't want to eject the project, I manually move all the build folders a couple of levels up so that it is on the same level as the app folders after the build process. That way I only have to include one path into to STATICFILES_DIRS. But I'm wondering if there is an automatic way of doing this.
I've been looking at other projects of django and React but unfortunately, most are rather small so they don't cover this case.
I was wondering if anyone had the same thoughts or maybe some nice big projects on github I can have a look at? Or am I wrong and by default having its own create react app in the separated apps makes sense?

Deployed django app to heroku missing CSS / static files

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.

Django pipeline - How to serve static files after running collectstatic?

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.

CSS not loading into Django template. Works when run locally

On my local PC I can do "python manage.py runserver" and the site runs perfectly, CSS and all. I just deployed the site to a public server and while most things work, CSS (and the images) are not loading into the templates.
I found some other questions with a similar issue, but my code did not appear to suffer from any of the same problems.
Within the Django project settings the same python function is being used to allow the app to see the templates and the static CSS / image files. The templates are being found by the views and are loading without issue.
Both from settings.py:
STATICFILES_DIRS = (
os.path.join(os.path.dirname(__file__), 'templates/css').replace('\\','/'),
os.path.join(os.path.dirname(__file__), 'content').replace('\\','/'),
)
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), 'templates').replace('\\','/'),
)
In the base.html file which the rest of the templates all extend:
<head>
{% load staticfiles %}
<link rel="stylesheet" type="text/css" href="{% static "style.css" %}" media="screen">
</head>
Directory structure:
|project_root/
|--manage.py
|--project/
| |--settings.py
| |--__init__.py
| |--content/
| | |--header.jpg
| |--templates/
| | |--base.html
| | |--css/
| | | |--style.css
My first thought when the CSS didn't load is that Django couldn't find the style.css file, but since I am using the same "os.path.dirname(file)" technique as with the templates, I am not sure this is the case.
What do I have wrong here?
Edit:
I neglected to mention that both the PC and server are running Python 2.7.5 and Django 1.5.5.
You never mentioned it in your post, so I am guessing:
You never ran ./manage.py collectstatic
collectstatic finds all static files (css, images, js) and puts them in a directory (Choose this directory with the django setting STATIC_ROOT) Then you point your webserver to that directory
You should deploy the static files using your server and not django.
The official documentation mentiones using collectstatic but unless your static files are messed up it's usually not a requirement. You just need to have some directory containing all your static files. Then you just push it with the server to the same place django will be looking.
Say you're STATIC_URL is '/static/', so you need to add an alias which would map '/static/' to the static directory. For example, using Apache, you should add this line to your http.conf:
Alias /static/ /path/to/mysite.com/static/
That's it! This thing goes true to media files as well, and it'd be wise to remove any serving of static files done by django for the development server (these kinds of urls). Finally, check out the documentation for even more information regarding other types of deployment

Static folders structure in Django 1.4?

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.

Categories