Let's suppose I have an HTML page (base.html) that must include one JavaScript file.
<script type="text/javascript" src="/js/main.js"></script>
It is my understanding that a Django project is not hosted in a public folder. Rather, requests are routed to views.py which generates a response.
Let's suppose my project directory looks like this
- project
- project_app
- views, models, ecc…
- templates
- base.html
- css
- main.css
- js
- main.js
How come base.html can reference main.css and main.js? If I access myserver.com/js/main.js this should not return anything (as the template folder is not public). Yet the browser need to access those file and I need to include them.
Do I need to write a specific URL rule to redirect requests to /js/main.js to the actual js file or what sort of magic can make a simple html include works?
The usual method is to keep your CSS, javascript, and similar files in a static folder and serve them to your html. General Django documentation can be found here.
In a nutshell, your directory will look like this:
- project
- project_app
- views, models, ecc…
- templates
- base.html
- static
- css
- main.css
- js
- main.js
Then, your base.html will reference the file using:
<script type="text/javascript" src="/static/js/main.js"></script>
The docs I referenced at the top show how to serve static files in production. Lots of people use a content delivery network (CDN) to serve their static files. Amazon's S3 service is an example of this. Then, you'll change the STATIC_URL setting in your settings.py to your S3 bucket (or similar network). You can then reference the STATIC_URL in your templates.
{% load static %}
...
<script type="text/javascript" src="{% static 'js/main.js' %}"></script>
...
You'll use commands like ./manage.py collectstatic to collect your static files and move them to your CDN at certain times. Basics of collectstatic can be found here.
You need to put all your static files in STATIC_ROOT folder by using command django-admin.py collectstatic and serve this folder. More details and explanation you can find here:
https://docs.djangoproject.com/en/dev/howto/static-files/#managing-static-files-css-images
Related
My project structure looks like this:
/project home
app.py
/templates/index.html
/templates/assets
and my index.html file has several references to relative stylesheets that look like this:
<link rel="stylesheet" href="assets/css/slick.css">
<link rel="stylesheet" href="assets/css/slick-theme.css">
Same for various JS files that exist in assets/js. Now when I load the page, I get this error:
Loading failed for the <script> with source “http://localhost:5000/assets/js/popper.min.js”. localhost:5000:564:1
There are many of these messages and in the python debugger I see:
127.0.0.1 - - [24/Dec/2019 18:29:16] "GET /assets/js/main.js HTTP/1.1" 404
I tried googling and changing this line in Flask
STATIC_URL_PATH = '/templates/assets/' # Where the css is stored
STATIC_FOLDER = '/templates/assets/'
app = flask.Flask(__name__, static_folder=STATIC_FOLDER,
static_url_path=STATIC_URL_PATH)
But still when I click the index.html page in templates its able to load fine with all the CSS and JS and images, but from Flask, its like the CSS is stripped out.
First, make sure that the templates folder is in the same directory as your app.py:
.
├── app.py
└── templates
└── assets
Then create the Flask instance like this:
STATIC_FOLDER = 'templates/assets'
app = Flask(__name__,
static_folder=STATIC_FOLDER)
1st, /templates and templates (without /) are 2 different paths. The 1st one refers to a templates folder under the root path / of your system, which certainly isn't the one you want. The 2nd one refers to a templates folder in the same directory, which is the one you want.
2nd, there is no need to specify static_url_path if it's just the same as the static_folder, because that's the default behavior ("Defaults to the name of the static_folder folder").
Then, in your HTML files, instead of hardcoding the paths to the assets folder, let Flask build the URL for you. See the Static Files section of the Flask docs:
To generate URLs for static files, use the special 'static' endpoint
name:
url_for('static', filename='style.css')
By default, it will look for static files under the static folder (ex. static/style.css) because that it is the default value for the static_folder parameter in the Flask constructor. When you set it to templates/assets, Flask will use that and will automatically build the correct URL with url_for.
<link rel="stylesheet" href="{{ url_for('static', filename='css/slick.css') }}">
Note:
Make sure that, when testing the loading of static files, clear your browser's cache first or test your app on private/incognito mode of your browser, to force re-downloading of static files.
I'm testing one and the same application both on the default Django server and on Apache and I see a lot of big differences. I managed to resolve some of them, but at this moment I'm unable to resolve a major difference. So, in project settings.py file I have this code:
MODULES_DIR = BASE_DIR + '/system/modules/'
for item in os.listdir(MODULES_DIR):
stat = os.path.join(MODULES_DIR, item + '/static')
if os.path.isdir(os.path.join(MODULES_DIR, item)):
INSTALLED_APPS += ('system.modules.%s' % item, )
STATICFILES_DIR += (stat, )
APPS_DIR = true
This code is supposed to populate INSTALLED_APPS dynamically, based on the contents of BASE_DIR + '/system/modules/' folder. In other words, if there is a folder inside /modules, this folder becomes an application. Likewise, I build dynamically STATICFILES_DIR - in this case it is supposed, that every single folder/application (which is inside /modules folder) has a /static folder with static contents - js, css etc. For example, it may be such a construct:
\modules
\DefaultModule
__init__.py
urls.py
views.py
\static
test.js
\templates
DefaultModule.html
And DefaultModule.html in this example loads static files like this:
<html>
<head>
{% load static from staticfiles %}
<script type="text/javascript" src="{% static "test.js" %}"></script>
It is rather interesting, but on default Django server this logic works perfectly, so that when I go in my browser to localhost/DefaultModule/, I see a template DefaultModule.html loaded and I see test.js file loaded from http://localhost/DefaultModule/static/. However, on Apache the template is rendered too, but the test.js file is loaded from http://localhost/static/ what eventually results in a 404 NOT FOUND error. So, for some reason Apache server does not take into account STATICFILES_DIR. And yes I checked its (I mean STATICFILES_DIR) contents and it is the same. In both cases STATICFILES_DIR contains modules/DefaultModule/static/, but on Apache it is ignored for some reason. Hope someone can help. Thanks!
I think you should read the Django docs on static files. Looks like you're falling into the simple and old Django Static File Hosting an Apache
Check it out and let us know.
I could load css file on Django html like this
{% load staticfiles %}
<link rel="stylesheet" href="{% static "css/style.css" %}">
I wonder why I can't load css file that is under templates folder.
<link rel="stylesheet" href="css/style.css">
Is there a way to load file that is under templates folder on Django HTML?
Why does Django wants me to put {% static "css/style.css" %} this format on all static files? Is it because much faster to load?
What If I load file that is under templates folder? Is it slow to load?
Templates and static assets are two differents types of assets that need to be managed differently for security purposes.
All js, css and images files need to be provided to clients in order for your website to be working. They are handled from the client side so they need to be available. So static asset folder is made to be available, if you check view source and follow the link of these assets you'll see they can be opened directly in your broswer.
Templates however are used by django itself to generate the output that is set via your views. When a user opens a page, he doesn't access the template itself but the rendering made by django. So the template folder isn't accessible to end user by design, including the files that are in it. So the only things a user can access from a django application are the responses given by the views, that are based on urls patterns and the templates, and assets that are in static folder. So you can't, and shouldn't, link to static assets from anywhere else but your static folder.
As I can see it, you have missed the concept of the templates and the static files in Django.
First of all, there are two independent mechanisms: loading a template file (your future HTML file) and loading your static files (css, js, images).
When loading a template Django uses TEMPLATE_LOADERS (docs), which are basically defined in your settings.py as:
TEMPLATE_LOADERS = (
# Loads templates from DIRS setting:
'django.template.loaders.filesystem.Loader',
# Loads templates from your installed apps:
'django.template.loaders.app_directories.Loader',
)
You can define a location of yout templates by setting DIRS (if you are using Django >= 1.8) or TEMPLATE_DIR (if Django < 1.8). There are several more steps in rendering your template such as: template context processors and so on, but it is all listed in the documentation.
Now about static files.
Static files are served by django.contrib.staticfiles app (docs) when DEBUG = True. In production it is done by Nginx, Apache or other Http-Servers.
When loading a static file Django uses STATICFILES_FINDERS. They are usially defined as:
STATICFILES_FINDERS = (
# Loads static files from STATICFILES_DIRS:
"django.contrib.staticfiles.finders.FileSystemFinder",
# Load static files from installed apps:
"django.contrib.staticfiles.finders.AppDirectoriesFinder"
)
There are two main settings to care about: STATIC_URL and STATICFILES_DIRS.
STATIC_URL is basically just a prefix, which is used to get your static files. It is almost always just '/static/'. And in STATICFILES_DIRS there are paths to your static files folders. It is sometimes extended to include node_modules, bower_components or things like that.
When dealing with static files in templates you need to append your STATIC_URL to your file's URL. The easiest way to do that is {% static %} tag.
A lot of confusion comes with STATIC_ROOT. It is just a path, where all your static files will be collected in production after running collectstatic management command.
I'm trying to do the following:
Having a file structure like the following:
/app
/static
/start
/css
/js
- index.html
/templates
Id like to know how I can serve this index.html and make this load its CSS and JS without using url_for('static', filename='') or other kind of serving trough Flask.
Basically, I want to put http://local.com/start and trough Flask serve index.html which will load its own css and js like <link href="css/style.css" rel="stylesheet">
I tried send_from_directory('/static/start', "index.html") and app.send_static_file('index.html') but they don't work.
I also tried current_app.send_static_file('start/index.html') but this only serves the html. It doesn't make the index.html load its own CSS and JS.
I got the information from these links
How to serve static files in Flask
python flask - serving static files
Flask: How to serve static html?
They don't do what I want (or maybe I'm doing it wrong).
Thanks in advance, if there is more info needed just tell me.
You can load a regular html file as a jinja template. Just call render without any parameters.
For some reason beyond me my html page is not finding my stylesheet. I'm using the Django framework if that helps at all. I'm running it on a localhost currently.
Html:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<link rel="stylesheet" href="../fitness/templates/masterpage.css" type="text/css">
</head>
<body>
<h1> MasterPage</h1>
{% block content %} {% endblock %}
</body>
</html>
masterpage.css
h1 {
color: #fff;
}
Thanks guys.
For serving static files, like CSS, django has the staticfiles lib:
https://docs.djangoproject.com/en/dev/howto/static-files/ - development version
https://docs.djangoproject.com/en/1.4/howto/static-files/ - Django 1.4
https://docs.djangoproject.com/en/1.3/howto/static-files/ - Django 1.3
Note that this requires a recent version of Django, as it's a quite recent addition
My guess is that the URL of the CSS matches no patterns in your urls.py, and thus returns an error
According to css link your paths may be:
[same root]/fitness/templates
[same root]/[maybe something else?]/current (the one that has the
displayed html)
Seeing your comment (answer) to Chris I suggest you to change the css link to:
/fitness/templates/masterpage.css
and ensure that you have masterpage.css under the corresponding physical path
The SHORT ANSWER HERE: In your settings.py make sure that you set a folder for STATIC_DIRS, a STATIC_URL (usually just '/static/'). Set a STATIC_ROOT setting of myproject/static/. Leave this folder empty. Add one folder under STATIC_DIRS call it myprojet/assets/. Then in assets/ have css, img, and js. Now you can access all assets in these organized folders via this location no matter what folder its in. {{ STATIC_URL }}/main.css {{ STATIC_URL }}/banner.png Also as a last resort run python manage.py collectstatic at your shell, and make sure that in your settings.py you have uncommented Django's static file handlers. (They are uncommented by default.)
Django Best Practices THE LONG ANSWER READ ONWARDS(in my limited experience).
Since they introduced the STATIC_DIRS { } setting I have always left the myproject/static/ directory empty. (During deployment it will be necessary to run python manage.py collectstatic command on your server to collect all of the admin files from site-packages and other things that your static server will be serving. So leave it empty for all that mess that goes in there later. Use a different folder for your "assets".)
I have a directory called src, many call it media also at the project level. Django 1.4 project level with manage.py not with your settings.py. I add myproject/src/ to the STATIC_DIRS setting. It is a tuple that should contain strings. Inside the src/ directory I have js, img, css. The coolest thing about all of the STATIC_DIRS you may decide to create is they can all be accessed via
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}/main.css" />
Note: You can do this even though your directory structure for css files may be several nested folders deep or in this case myproject/src/css/main.css . Django does not care about your directory structure. Django in general is quite loosely coupled from it's elements. For example, it's very easy to plugin another Pythonic templating language of your choice. Just as it's easy to set your STATIC_URL setting and STATIC_DIRS so Django knows where to look and it serves them all from /static/.