4π
Cause of errors
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.
Possible Solution
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('c**kpit/', include("c**kpit.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)
1π
Use of STATIC_URL
First of all, STATIC_URL
will be the url where the static files will be served. So if you set STATIC_URL='/'
and then navigate to http://127.0.0.1:8000/index.html
it will essentially serve the index.html
from within the static folder of your Django application. If you go to http://127.0.0.1:8000/
youβre at your βstatic folder rootβ, and as you can see, a directory index is forbidden. So donβt use STATIC_URL='/'
Location of the files
The tutorial you followed adds the build folder of the SPA to the templates in your Django settings.py
file.
So you should try and add:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(os.path.dirname(BASE_DIR), 'frontend', 'dist')], # <== ADDED THIS
'APP_DIRS': True,
'OPTIONS': {
# removed to keep this example small
},
]
or if you want to point to your static files as template directory:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'static')],
'APP_DIRS': True,
'OPTIONS': {
# removed to keep this example small
},
]
However I donβt think it is best practice since static files (images, JS, CSS) have their own qualification in Django.
Note on os.path
Also, for your STATICFILES_DIRS
, thatβs not how os.path.join()
works. The first argument should be a path you want to join with one or more path components, the components are then passed as the next arguments. Furthermore, BASE_DIR
is not at the right directorylevel, as you can see when you printed out the BASE_DIR
path. You need the parent of the BASE_DIR
directory. To get the path of the parent directory, you can do os.path.dirname(BASE_DIR)
, because BASE_DIR
is a path. So applying this we get:
STATICFILES_DIRS = [
os.path.join(os.path.dirname(BASE_DIR), frontend, dist),
]
Final note
I do feel that it might be an anti pattern to have your SPA served by Django without it being completely self contained in the Django BASE_DIR
(hence the name, base directory). But I donβt know the source for it, or exactly how best practice this.
- Django 1.5 admin inline extra
- Django ModuleNotFoundError
- Django on Heroku β Broken Admin Static Files
1π
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 c**kpit 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.
- Django makemessages not creating newly added languages
- Django collectstatic no such file or directory
- Determine empty template variable in Django
- Django queryset return single value
0π
First things first! If you want to serve your UI from Django as static files for the production, itβs a bad idea! You need to consider using nginx or similar web server to serve static files for you.
The TemplateView
in your urls.py
is a bit problematic. Since your static files are served under STATIC_URL = '/static/'
in your first scenario, the urls for js and css files does not match. You might edit the files and put static
template tags inside index.hml
but itβs not a good idea as well. When you do changes on vuejs side, you need to build and replace the package directly and your site is updated. So the this line needs to be deleted forever, index.html has to be treated as static file:
re_path('', TemplateView.as_view(template_name='index.html')),
When you changed STATIC_URL = '/'
you may access all of your static files. If you run django in debug = True
it serves static files automatically. Otherwise you need to add static url conf to the file. (DO NOT FORGET, This is not good for production!)
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('c**kpit/', include("c**kpit.urls")),
]
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
With this setup you need to be careful about your urls and static file namings. They might override each other.
P.S: Thank you for such a detailed question.
- How to create a group permission in django
- Django-registration "remember me"
- How do I create a wheel from a django app?
- How to display month name by number?
0π
There is a dumb way to fix this issue.
This issue is about that html built by VueJS will get js and css from path like these /js/app.12312sd.js
and /css/app.dsfeewj.css
.
Default setting of static file root path is /static/
, so you only need to change each /js/...
and /css/...
in index.html
manually or use sed
or something else to replace them to /static/js/.../
and /static/css/.../
.
You cannot replace STATIC_URL
to /
because it the root url for your website.
After you edit it, it will look like this, and then server your django server it will work well.
0π
Before building your frontend put the css/ and js/ in a directory named βstaticβ leaving the index.html as it is. Then when you run yarn build
your directory structure would be as follows β
c**kpit
βββ backend/
β βββ c**kpit/
β β βββ views.py
β β βββ css/
β β βββ etc..
β βββ settings/
β β βββ settings.py
β βββ manage.py
βββ frontend/
βββ dist/
βββ static/
β βββ css/
β βββ js/
βββ index.html
Setup your BASE_DIR and a FRONTEND_DIR to point towards βc**kpit/frontend/distβ for quick use later on.
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
FRONTEND_DIR = os.path.join(os.path.dirname(BASE_DIR),'frontend','dist')
Now either copy frontend static files to your backend directory as you did earlier β
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(FRONTEND_DIR,'static/'),
]
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
OR you could directly point your backend to serve from the built frontend directory instead of copying it again. (I somehow always do this)
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(FRONTEND_DIR,'static/')
Include your built frontend directory in your template directories for django to be able to serve index.html
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [FRONTEND_DIR],
'APP_DIRS': True,
'OPTIONS': {
# removed to keep this example small
},
},
]
Now run your server
$ python manage.py collectstatic
$ python manage.py runserver
If later you decide on deploying this online you could do that easily using this configuration itself by setting Nginx to serve static files from your static directory.
Hope this helps π
Clearing your confusion in your [EDIT]
STATIC_ROOT points to the directory on your system. STATIC_URL refers to the URL at which your static files that are present in your STATIC_ROOT would be accessed while using your website.
Letβs say you have a file script.js in your directory as shown
c**kpit
βββ backend/
β βββ c**kpit/
β β βββ views.py
β β βββ css/
β β βββ etc..
β βββ settings/
β β βββ settings.py
β βββ manage.py
βββ frontend/
βββ dist/
βββ static/
β βββ css/
β βββ js/
β βββ script.js
βββ index.html
and you have set your STATIC_ROOT to point towards βc**kpit/frontend/dist/static/β.
Now if you set your STATIC_URL as βstatic/β you would be able to access that script at http://127.0.0.1:8000/static/js/script.js
Alternatively, if you set your STATIC_URL to βxcsdf/β you would access your js file at http://127.0.0.1:8000/xcsdf/js/script.js
- Updating JSONField in django rest framework
- Django β UpdateView with inline formsets trying to save duplicate records?
- Whats the best way to extend Anonymous User in Django?