I'm building a website using a Django backend and Vuejs frontend. In development I started the backend and the frontend separately with python manage.py runserver
and yarn serve
respectively. This worked great and I now want to deploy the website. To do this I ran yarn build
, which created a dist/
folder in my frontend folder. So my structure was like this:
cockpit
├── backend/
│ ├── cockpit/
│ │ ├── views.py
│ │ ├── css/
│ │ └── etc..
│ ├── settings/
│ │ └── settings.py
│ └── manage.py
└── frontend/
└── dist/
├── index.html
├── css/
└── js/
I now want to serve the sources in frontend/dist/
from my django project so that I can run everything using uwsgi. To do this I'm trying to follow this description. I have the following settings/urls.py
from django.contrib import admin
from django.urls import include, path, re_path
from django.views.generic import TemplateView
urlpatterns = [
path('admin/', admin.site.urls),
path('cockpit/', include("cockpit.urls")),
re_path('', TemplateView.as_view(template_name='index.html')),
]
and set the following settings in my settings.py:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['static'], # <== ADDED THIS
'APP_DIRS': True,
'OPTIONS': {
# removed to keep this example small
},
},
]
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, '../frontend/dist'),
]
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
print("BASE_DIR:", BASE_DIR)
print("STATIC_ROOT:", STATIC_ROOT)
print("STATICFILES_DIRS:", STATICFILES_DIRS)
And the prints show me this:
BASE_DIR: /home/kramer65/repos/cockpit/backend
STATIC_ROOT: /home/kramer65/repos/cockpit/backend/static/
STATICFILES_DIRS: ['/home/kramer65/repos/cockpit/backend/../frontend/dist']
Then I ran `python manage.py collectstatic:
$ python manage.py collectstatic
150 static files copied to '/home/kramer65/repos/cockpit/backend/static'.
So it now looks like this:
cockpit
├── backend/
│ ├── cockpit/
│ │ ├── views.py
│ │ ├── css/
│ │ └── etc..
│ ├── settings/
│ │ └── settings.py
│ └── manage.py
│ └── static/
│ ├── index.html
│ ├── css/
│ └── js/
└── frontend/
└── dist/
├── index.html
├── css/
└── js/
I tested it by running the (node) http-server
from the backend/static/
folder. In the browser the website loads and runs perfect. Below is the output from the command line:
$ http-server
Starting up http-server, serving ./
Available on:
http://127.0.0.1:8080
http://192.168.0.104:8080
Hit CTRL-C to stop the server
[2020-05-18T13:50:58.487Z] "GET /" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0"
(node:5928) [DEP0066] DeprecationWarning: OutgoingMessage.prototype._headers is deprecated
[2020-05-18T13:50:58.671Z] "GET /css/chunk-vendors.2c7f3eba.css" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0"
[2020-05-18T13:50:58.679Z] "GET /css/app.e15f06d0.css" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0"
[2020-05-18T13:50:58.681Z] "GET /js/chunk-vendors.9c409057.js" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0"
[2020-05-18T13:50:58.687Z] "GET /js/app.c930fce5.js" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0"
I stopped this http-server
, started the Django dev server and opened the browser. The terminal shows me this:
$ python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
May 18, 2020 - 17:57:00
Django version 3.0.6, using settings 'settings.settings'
Starting ASGI/Channels version 2.4.0 development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
HTTP GET / 200 [0.22, 127.0.0.1:33224]
HTTP GET /static/debug_toolbar/css/print.css 200 [0.04, 127.0.0.1:33232]
HTTP GET /static/debug_toolbar/css/toolbar.css 200 [0.05, 127.0.0.1:33234]
HTTP GET /static/debug_toolbar/js/toolbar.js 200 [0.02, 127.0.0.1:33232]
HTTP GET /static/debug_toolbar/js/toolbar.timer.js 200 [0.04, 127.0.0.1:33234]
HTTP GET /js/chunk-vendors.9c409057.js 200 [0.80, 127.0.0.1:33228]
HTTP GET /css/chunk-vendors.2c7f3eba.css 200 [0.94, 127.0.0.1:33224]
HTTP GET /js/app.c930fce5.js 200 [0.98, 127.0.0.1:33230]
HTTP GET /css/app.e15f06d0.css 200 [0.99, 127.0.0.1:33226]
HTTP GET /favicon.ico 200 [0.09, 127.0.0.1:33226]
In the browser console I see the sources seem to be loaded, but some seem to be empty (0 bytes) and the screen doesn't show anything. Below is a screenshot of the results and a screenshot of the Static Files tab in the Django Debug Bar.
Does anybody know why it isn't serving those files correctly in Django?
[EDIT]
I just found that if I change
STATIC_URL = '/static/'
to
STATIC_URL = '/'
it works correctly when I go to http://127.0.0.1:8000/index.html
, but now http://127.0.0.1:8000/
gives me this error:
[EDIT 2]
Ok, so following the advice of @geek_life I changed the values in my settings file to:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
PROJECT_NAME = 'cockpit'
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, PROJECT_NAME, "static/")
STATICFILES_DIRS = [os.path.join(BASE_DIR, '../frontend/dist')]
print("## BASE_DIR:", BASE_DIR)
print("## STATIC_ROOT:", STATIC_ROOT)
print("## STATICFILES_DIRS:", STATICFILES_DIRS)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['cockpit/static/'], # <= THIS IS WHAT I CHANGED
'APP_DIRS': True,
'OPTIONS': {} # And here some options
},
]
Which prints out
## BASE_DIR: /home/kramer65/repos/cockpit/backend
## STATIC_ROOT: /home/kramer65/repos/cockpit/backend/cockpit/static/
## STATICFILES_DIRS: ['/home/kramer65/repos/cockpit/backend/../frontend/dist']
And in the file settings/urls.py
I (still) got this:
urlpatterns = [
path('admin/', admin.site.urls),
path('cockpit/', include("cockpit.urls")),
re_path('', TemplateView.as_view(template_name='index.html')),
]
I then copied the static/
folder with the built vuejs-ap from cockpit/backend/
to cockpit/backend/cockpit/
.
Unfortunately I still get the same result. The index.html loads, but the js and css files still don't. Any other ideas?
django. contrib. staticfiles collects static files from each of your applications (and any other places you specify) into a single location that can easily be served in production.
To serve static files for Go 1.12+ in the standard environment, you define the handlers in your app. yaml file using either the static_dir or static_files elements. The content in the static files or static directories are unaffected by the scaling settings in your app.
STATICFILES_DIRS: By default, static files are stored at the app-level at <APP_NAME>/static/ . The collectstatic command will look for static files in those directories. You can also tell Django to look for static files in additional locations with STATICFILES_DIRS .
Make sure that django.contrib.staticfiles is included in your INSTALLED_APPS. In your settings file, define STATIC_URL, for example: In your templates, use the static template tag to build the URL for the given relative path using the configured STATICFILES_STORAGE. Store your static files in a folder called static in your app.
It seems unlikely that this is a Django issue, since you’ve shown that URLs in the link elements are correct, that you can directly load the CSS via a browser request and that the runserver terminal is not showing requests for the CSS when you complete a normal page load.
This method is grossly inefficient and probably insecure , so it is unsuitable for production. See How to deploy static files for proper strategies to serve static files in production environments. Your project will probably also have static assets that aren’t tied to a particular app.
Store your static files in a folder called static in your app. For example my_app/static/my_app/example.jpg. In addition to these configuration steps, you’ll also need to actually serve the static files.
For the first case
STATIC_URL = '/static/'
Django tries to look for static files in the backend/static/
folder only in the case where anything with url with /static/
i.e. for e.g. /static/css/*
or /static/js/*
is mentioned in your index.html
, but that is not the case here index.html
has file references like /css/*
and /js/*
, hence they are not found.
The reason this case works in the blog example is due to the same reason i.e. their template files are kept under a '../frontend/build
directory and static files are in '../frontend/build/static' hence the index.html
will look for static/js/*
instead of a /js/*
hence /static/
url location is accessed in Django, which then looks for the files in backend/static
correctly
This is why, in your code, setting it to second case i.e.
STATIC_URL = '/'
gets the urls for static files correctly to /css/*
and /js/*
and even your /index.html
can be thought of as a static file i.e. all these urls are considered static and are searched in the backend/static/
folder and hence appearing correctly in the browser.
But now the URLs are messed up i.e. this:
re_path('', TemplateView.as_view(template_name='index.html')),
can be treated as Django looking for this location: /
, but it is already reserved for searching static files and not including any file name after /
means you are not looking for any file.
Django allows custom url patterns i.e. you can create 2 new variables in settings.py i.e.
STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
STATIC_JS_URL = "/js/"
STATIC_JS_ROOT = os.path.join(STATIC_ROOT, "js/")
STATIC_CSS_URL = "/css/"
STATIC_CSS_ROOT = os.path.join(STATIC_ROOT, "css/")
and then configure your urls.py
from django.contrib import admin
from django.urls import include, path, re_path
from django.views.generic import TemplateView
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('cockpit/', include("cockpit.urls")),
re_path('', TemplateView.as_view(template_name='index.html')),
]
urlpatterns += static(settings.STATIC_JS_URL, document_root=settings.STATIC_JS_ROOT)
urlpatterns += static(settings.STATIC_CSS_URL, document_root=settings.STATIC_CSS_ROOT)
I had this problem a long time ago and I solved it with a simple solution. It's too simple. As I see, your static folder is not in your app root and it's in wrong place. Put it in your app root...because Django is looking for the static folder inside the main root of your app, where views.py is in there. Maybe you have 5 apps or more. Django doesn't care about the number of apps you have, Django only looks for your static folder in your app root. But your templates folder can be in your project root. So , put your static folder in your app root. In this case I mean inside cockpit root.
And then you have to add this changes in settings.py
PROJECT_NAME = '---Your projects name---'
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, PROJECT_NAME, 'static/')
EXTERNAL_APPS = [
'django.contrib.staticfiles',
]
Good Luck.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With