So this is embarrassing. I've got an application that I threw together in Flask and for now it is just serving up a single static HTML page with some links to CSS and JS. And I can't find where in the documentation Flask describes returning static files. Yes, I could use render_template but I know the data is not templatized. I'd have thought send_file or url_for was the right thing, but I could not get those to work. In the meantime, I am opening the files, reading content, and rigging up a Response with appropriate mimetype:
import os.path
from flask import Flask, Response
app = Flask(__name__)
app.config.from_object(__name__)
def root_dir(): # pragma: no cover
return os.path.abspath(os.path.dirname(__file__))
def get_file(filename): # pragma: no cover
try:
src = os.path.join(root_dir(), filename)
# Figure out how flask returns static files
# Tried:
# - render_template
# - send_file
# This should not be so non-obvious
return open(src).read()
except IOError as exc:
return str(exc)
#app.route('/', methods=['GET'])
def metrics(): # pragma: no cover
content = get_file('jenkins_analytics.html')
return Response(content, mimetype="text/html")
#app.route('/', defaults={'path': ''})
#app.route('/<path:path>')
def get_resource(path): # pragma: no cover
mimetypes = {
".css": "text/css",
".html": "text/html",
".js": "application/javascript",
}
complete_path = os.path.join(root_dir(), path)
ext = os.path.splitext(path)[1]
mimetype = mimetypes.get(ext, "text/html")
content = get_file(complete_path)
return Response(content, mimetype=mimetype)
if __name__ == '__main__': # pragma: no cover
app.run(port=80)
Someone want to give a code sample or url for this? I know this is going to be dead simple.
In production, configure the HTTP server (Nginx, Apache, etc.) in front of your application to serve requests to /static from the static folder. A dedicated web server is very good at serving static files efficiently, although you probably won't notice a difference compared to Flask at low volumes.
Flask automatically creates a /static/<path:filename> route that will serve any filename under the static folder next to the Python module that defines your Flask app. Use url_for to link to static files: url_for('static', filename='js/analytics.js')
You can also use send_from_directory to serve files from a directory in your own route. This takes a base directory and a path, and ensures that the path is contained in the directory, which makes it safe to accept user-provided paths. This can be useful in cases where you want to check something before serving the file, such as if the logged in user has permission.
from flask import send_from_directory
#app.route('/reports/<path:path>')
def send_report(path):
return send_from_directory('reports', path)
Do not use send_file or send_static_file with a user-supplied path. This will expose you to directory traversal attacks. send_from_directory was designed to safely handle user-supplied paths under a known directory, and will raise an error if the path attempts to escape the directory.
If you are generating a file in memory without writing it to the filesystem, you can pass a BytesIO object to send_file to serve it like a file. You'll need to pass other arguments to send_file in this case since it can't infer things like the file name or content type.
If you just want to move the location of your static files, then the simplest method is to declare the paths in the constructor. In the example below, I have moved my templates and static files into a sub-folder called web.
app = Flask(__name__,
static_url_path='',
static_folder='web/static',
template_folder='web/templates')
static_url_path='' removes any preceding path from the URL (i.e.
the default /static).
static_folder='web/static' to serve any files found in the folder
web/static as static files.
template_folder='web/templates' similarly, this changes the
templates folder.
Using this method, the following URL will return a CSS file:
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">
And finally, here's a snap of the folder structure, where flask_server.py is the Flask instance:
You can also, and this is my favorite, set a folder as static path so that the files inside are reachable for everyone.
app = Flask(__name__, static_url_path='/static')
With that set you can use the standard HTML:
<link rel="stylesheet" type="text/css" href="/static/style.css">
I'm sure you'll find what you need there: http://flask.pocoo.org/docs/quickstart/#static-files
Basically you just need a "static" folder at the root of your package, and then you can use url_for('static', filename='foo.bar') or directly link to your files with http://example.com/static/foo.bar.
EDIT: As suggested in the comments you could directly use the '/static/foo.bar' URL path BUT url_for() overhead (performance wise) is quite low, and using it means that you'll be able to easily customise the behaviour afterwards (change the folder, change the URL path, move your static files to S3, etc).
You can use this function :
send_static_file(filename)
Function used internally to send static
files from the static folder to the browser.
app = Flask(__name__)
#app.route('/<path:path>')
def static_file(path):
return app.send_static_file(path)
What I use (and it's been working great) is a "templates" directory and a "static" directory. I place all my .html files/Flask templates inside the templates directory, and static contains CSS/JS. render_template works fine for generic html files to my knowledge, regardless of the extent at which you used Flask's templating syntax. Below is a sample call in my views.py file.
#app.route('/projects')
def projects():
return render_template("projects.html", title = 'Projects')
Just make sure you use url_for() when you do want to reference some static file in the separate static directory. You'll probably end up doing this anyways in your CSS/JS file links in html. For instance...
<script src="{{ url_for('static', filename='styles/dist/js/bootstrap.js') }}"></script>
Here's a link to the "canonical" informal Flask tutorial - lots of great tips in here to help you hit the ground running.
http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world
A simplest working example based on the other answers is the following:
from flask import Flask, request
app = Flask(__name__, static_url_path='')
#app.route('/index/')
def root():
return app.send_static_file('index.html')
if __name__ == '__main__':
app.run(debug=True)
With the HTML called index.html:
<!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
</head>
<body>
<div>
<p>
This is a test.
</p>
</div>
</body>
</html>
IMPORTANT: And index.html is in a folder called static, meaning <projectpath> has the .py file, and <projectpath>\static has the html file.
If you want the server to be visible on the network, use app.run(debug=True, host='0.0.0.0')
EDIT: For showing all files in the folder if requested, use this
#app.route('/<path:path>')
def static_file(path):
return app.send_static_file(path)
Which is essentially BlackMamba's answer, so give them an upvote.
For angular+boilerplate flow which creates next folders tree:
backend/
|
|------ui/
| |------------------build/ <--'static' folder, constructed by Grunt
| |--<proj |----vendors/ <-- angular.js and others here
| |-- folders> |----src/ <-- your js
| |----index.html <-- your SPA entrypoint
|------<proj
|------ folders>
|
|------view.py <-- Flask app here
I use following solution:
...
root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ui", "build")
#app.route('/<path:path>', methods=['GET'])
def static_proxy(path):
return send_from_directory(root, path)
#app.route('/', methods=['GET'])
def redirect_to_index():
return send_from_directory(root, 'index.html')
...
It helps to redefine 'static' folder to custom.
app = Flask(__name__, static_folder="your path to static")
If you have templates in your root directory, placing the app=Flask(name) will work if the file that contains this also is in the same location, if this file is in another location, you will have to specify the template location to enable Flask to point to the location
So I got things working (based on #user1671599 answer) and wanted to share it with you guys.
(I hope I'm doing it right since it's my first app in Python)
I did this -
Project structure:
server.py:
from server.AppStarter import AppStarter
import os
static_folder_root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "client")
app = AppStarter()
app.register_routes_to_resources(static_folder_root)
app.run(__name__)
AppStarter.py:
from flask import Flask, send_from_directory
from flask_restful import Api, Resource
from server.ApiResources.TodoList import TodoList
from server.ApiResources.Todo import Todo
class AppStarter(Resource):
def __init__(self):
self._static_files_root_folder_path = '' # Default is current folder
self._app = Flask(__name__) # , static_folder='client', static_url_path='')
self._api = Api(self._app)
def _register_static_server(self, static_files_root_folder_path):
self._static_files_root_folder_path = static_files_root_folder_path
self._app.add_url_rule('/<path:file_relative_path_to_root>', 'serve_page', self._serve_page, methods=['GET'])
self._app.add_url_rule('/', 'index', self._goto_index, methods=['GET'])
def register_routes_to_resources(self, static_files_root_folder_path):
self._register_static_server(static_files_root_folder_path)
self._api.add_resource(TodoList, '/todos')
self._api.add_resource(Todo, '/todos/<todo_id>')
def _goto_index(self):
return self._serve_page("index.html")
def _serve_page(self, file_relative_path_to_root):
return send_from_directory(self._static_files_root_folder_path, file_relative_path_to_root)
def run(self, module_name):
if module_name == '__main__':
self._app.run(debug=True)
By default folder named "static" contains all static files
Here's a code sample:
<link href="{{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
Use redirect and url_for
from flask import redirect, url_for
#app.route('/', methods=['GET'])
def metrics():
return redirect(url_for('static', filename='jenkins_analytics.html'))
This servers all files (css & js...) referenced in your html.
One of the simple way to do. Cheers!
demo.py
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def index():
return render_template("index.html")
if __name__ == '__main__':
app.run(debug = True)
Now create folder name called templates.
Add your index.html file inside of templates folder
index.html
<!DOCTYPE html>
<html>
<head>
<title>Python Web Application</title>
</head>
<body>
<div>
<p>
Welcomes You!!
</p>
</div>
</body>
</html>
Project Structure
-demo.py
-templates/index.html
The issue I had was related to index.html files not being served for directories when using static_url_path and static_folder.
Here's my solution:
import os
from flask import Flask, send_from_directory
from flask.helpers import safe_join
app = Flask(__name__)
static = safe_join(os.path.dirname(__file__), 'static')
#app.route('/')
def _home():
return send_from_directory(static, 'index.html')
#app.route('/<path:path>')
def _static(path):
if os.path.isdir(safe_join(static, path)):
path = os.path.join(path, 'index.html')
return send_from_directory(static, path)
Thought of sharing.... this example.
from flask import Flask
app = Flask(__name__)
#app.route('/loading/')
def hello_world():
data = open('sample.html').read()
return data
if __name__ == '__main__':
app.run(host='0.0.0.0')
This works better and simple.
All the answers are good but what worked well for me is just using the simple function send_file from Flask. This works well when you just need to send an html file as response when host:port/ApiName will show the output of the file in browser
#app.route('/ApiName')
def ApiFunc():
try:
return send_file('some-other-directory-than-root/your-file.extension')
except Exception as e:
logging.info(e.args[0])```
The simplest way is create a static folder inside the main project folder. Static folder containing .css files.
main folder
/Main Folder
/Main Folder/templates/foo.html
/Main Folder/static/foo.css
/Main Folder/application.py(flask script)
Image of main folder containing static and templates folders and flask script
flask
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def login():
return render_template("login.html")
html (layout)
<!DOCTYPE html>
<html>
<head>
<title>Project(1)</title>
<link rel="stylesheet" href="/static/styles.css">
</head>
<body>
<header>
<div class="container">
<nav>
<a class="title" href="">Kamook</a>
<a class="text" href="">Sign Up</a>
<a class="text" href="">Log In</a>
</nav>
</div>
</header>
{% block body %}
{% endblock %}
</body>
</html>
html
{% extends "layout.html" %}
{% block body %}
<div class="col">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<input type="submit" value="Login">
</div>
{% endblock %}
The URL for a static file can be created using the static endpoint as following:
url_for('static', filename = 'name_of_file')
<link rel="stylesheet" href="{{url_for('static', filename='borders.css')}}" />
By default, flask use a "templates" folder to contain all your template files(any plain-text file, but usually .html or some kind of template language such as jinja2 ) & a "static" folder to contain all your static files(i.e. .js .css and your images).
In your routes, u can use render_template() to render a template file (as I say above, by default it is placed in the templates folder) as the response for your request. And in the template file (it's usually a .html-like file), u may use some .js and/or `.css' files, so I guess your question is how u link these static files to the current template file.
If you are just trying to open a file, you could use app.open_resource(). So reading a file would look something like
with app.open_resource('/static/path/yourfile'):
#code to read the file and do something
In the static directory, create templates directory inside that directory add all the html file create separate directory for css and javascript as flask will treat or recognize all the html files which are inside the template directory.
static -
|_ templates
|_ css
|_javascript
|_images
This is what worked for me:
import os
from flask import Flask, render_template, send_from_directory
app = Flask(__name__)
root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "whereyourfilesare")
#app.route('/', methods=['GET'])
def main(request):
path = request.path
if (path == '/'):
return send_from_directory(root, 'index.html')
else:
return send_from_directory(root, path[1:])
In my case, i needed all the files from a static folder to be accessible by the user, as well as i needed to use templates for some of my html files, so that common html code could be placed in the template and code gets reused. Here is how i achieved both of them together:
from flask import Flask, request, render_template
from flask.json import JSONEncoder
app = Flask(__name__, template_folder='static')
#app.route('/<path:path>')
def serve_static_file(path):
# In my case, only html files are having the template code inside them, like include.
if path.endswith('.html'):
return render_template(path)
# Serve all other files from the static folder directly.
return app.send_static_file(path)
And all of my files are kept under static folder, which is parallel to main flask file.
For example, to return an Adsense file I have used:
#app.route('/ads.txt')
def send_adstxt():
return send_from_directory(app.static_folder, 'ads.txt')
Related
I build a rest service in Deno (Oak) and also serve static files. However, when I run deno compile I would like to have those static files included into the single binary file that is ejected. Is this possible?
From what I can tell, neither Deno nor Oak have intentional support for this.
A downside of even doing this is that your binary file may become large. This isn't only an issue with distribution but may also slow loading and executing the binary.
Nevertheless, one way you can make "static" files available in a compiled binary is to encode the files as JavaScript modules (similar to using WebAssembly in Deno).
e.g. The following module encodes a static file, named example.txt, storing its file type, txt, and its contents, hello world\n. The contents are base64 encoded (thank you jsejcksn for the suggestion). You can encode and decode the contents other ways as well or even use different encodings depending on the file type if you like.
example.txt.ts:
export default {
type: "txt",
data: "aGVsbG8gd29ybGQK",
};
You can programmatically create modules like this from static files.
e.g. encode-as-module.ts:
import { extname } from "https://deno.land/std#0.155.0/path/mod.ts";
import { encode } from "https://deno.land/std#0.155.0/encoding/base64.ts";
const [inputPath, outputPath = `${inputPath}.ts`] = Deno.args;
const type = extname(inputPath).slice(1);
const bytes = await Deno.readFile(inputPath);
const script = /* JavaScript */ `export default {
type: "${type}",
data: "${encode(bytes)}",
};
`;
await Deno.writeTextFile(outputPath, script);
Usage:
deno run --allow-read --allow-write encode-as-module.ts example.txt
Once you have your static files encoded as modules you can then change your Oak app from serving them using send() to serving them using context.response (passing the type and body). More work will need to be done here to encode a list of all the static files, etc. but I think what's already provided here illustrates the idea sufficiently.
I am pretty new to python Django; I am trying to figure out what exactly I am missing from the last few hours.
here is my code structure
url.py
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('signup', views.signupuser, name="signupuser"),
path ('', views.home, name='home'),
path ('socialcard', views.create_social_card, name='create_social_card'),
path ('dashboard/', include('dashboard.urls')),
]
Then I created another URL set in the dashboard app; here is the code.
From django.shortcuts import render
# Create your views here.
def dashboard(request):
home="dashboard"
return render(request, 'dashboard.html', {'home':home})
I am getting the following error,
TemplateDoesNotExist at /dashboard/
dashboard.html
I don't know what I am missing, I have added the templates folder in the app and have also added the subfolder dashboard. like this dashboard/templates/dashboard, and then there reside dashboard.html
When I add the template path as base.html, it loads up an empty page, doesn't display any error. So I don't know what exactly I am missing.
Well as all beginners do silly mistakes...I forgot to define my app in the setting.
I would advise all beginners that add the app in the setting as soon as you start an app.
I have an Angular 2 application in which i wish to use wrapbootstrap. I do however have a problem with the fonts (bootstrap, font-awesome, google) as i do not know how to implement them.
When using the css file for wrapbootstrap is says it cannot find font awesome:
"Failed to load resource: the server responded with a status of 404 (Not Found) http://localhost:8000/fonts/font-awesome/fontawesome-webfont.woff2?v=4.4.0"
I cannot make sense of this as i can see the missing file(s) in resources in the chrome console on that exact address.
The font files are currently in a folder vi the following relative path from the css (application.css) file using them:
Which fits the required path in the css file:
I hope someone out there can provide some guidance as i am lost.
Thanks in advance
Solved
the problem was apparently the location of my fonts folder.
my file structure are as follows:
and i had firstly added the fonts/ relative to where the application.css file was. It had to be located in the root of my app (src)
Adding fonts installed with package manager is quite often a task. For instance, using font-awesome or any other similar library is a typical task one will need.
For this purpose, you can go through the following steps:
In tools/config/project.config.ts:
...
export class ProjectConfig extends SeedConfig {
PROJECT_TASKS_DIR = join(process.cwd(), this.TOOLS_DIR, 'tasks', 'project');
FONTS_DEST = `${this.APP_DEST}/fonts`;
FONTS_SRC = [
'node_modules/bootstrap/dist/fonts/**'
];
...
Create a file tools/tasks/project/build.fonts.ts:
import * as gulp from 'gulp';
import Config from '../../config';
export = () => {
return gulp.src(Config.FONTS_SRC)
.pipe(gulp.dest(Config.FONTS_DEST));
};
In gulpfile.ts (or in seed.tasks.json for newer versions of the Seed)
// Build dev.
gulp.task('build.dev', done =>
runSequence('clean.dev',
'tslint',
'build.assets.dev',
'build.fonts', // Added task;
'build.js.dev',
'build.index.dev',
done));
// Build prod.
gulp.task('build.prod', done =>
runSequence('clean.prod',
'tslint',
'build.assets.prod',
'build.fonts', // Added task;
'build.html_css.prod',
'build.js.prod',
'build.bundles',
'build.bundles.app',
'build.index.prod',
done));
// Build test.
gulp.task('build.test', done =>
runSequence('clean.dev',
'tslint',
'build.assets.dev',
'build.fonts', // Added task;
'build.js.test',
'build.index.dev',
done));
src
I have followed this guide, to set up a slightly different/better django project.
I am also trying to use static files, to load site wide files (like a site.css file for every page). To do so I'm following this guide also.
What I'm finding is that it's looking for http://localhost:8000/static/css/site.css to grab my css, when the css (on disk) is top-level-folder/static/css/site.css, and for context, top-level-folder is also where I've got my app and project folders, as well as manage.py (that is, app_folder, project folder and manage.py are siblings with the shared parent of top-level-folder).
Something like this:
top-folder
|-> app-folder (same name as top-folder)
|-> project-folder (same name as top-folder)
|-> static
My concern is that this isn't being found, as rather than having a settings.py file, I have a settings folder with several files in it (the base one is called base.py) as per the first guide.
Here's the relevant snippet from my base.py
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates'),
os.path.join(BASE_DIR, 'gantt_charts/templates/gantt_charts')]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),
)
And I also have this in there by default, STATIC_URL = '/static/' but I don't know if that's relevant.
So why doesn't Django know where my .css file is? Is it to do with my alternative set up?
Instead of changing your directory structure, it would be better to just change the BASE_DIR to reflect the extra level you have introduced:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
With that small change you can keep your static folder in the "right" place.
I've edited my settings (base.py) and I've moved my static folder.
Both the top level folder and the app have the same name, so I was getting which folder to put it in mixed up.
I now have:
top-folder
|-> project-folder (same name as top-folder)
|-> static
|-> app-folder
Rather than:
top-folder
|-> app-folder (same name as top-folder)
|-> project-folder (same name as top-folder)
|-> static
My basy.py snippit now looks like:
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates'),
os.path.join(BASE_DIR, 'gantt_charts/templates/gantt_charts')]
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'),
]
See how I've nestled a os.path.abspath in there? That's the other important step I think.
Also worth noting that you can add debugging print-outs to your settings (it's Python code after all) which really helped. For instance:
print ("Base Dir is at:",BASE_DIR)
print ("Static Dir is at:",STATICFILES_DIRS)
And this runs each time the runserver command triggers.
I'm really confused. I'm using Django 1.4 and I've been searching for this the whole day, and it seems like that everything has changed in the latest version of Django and the documentation isn't helpful at all (at least to me). Please help me attach a CSS file to my template.
So, this is my settings.py file
STATIC_ROOT = 'F:/Django/mysite/mysite/static/'
STATIC_URL = '/static/'
STATICFILES_DIRS = (
"F:/Django/mysite/mysite/static/",
)
Here's my urls
from django.conf.urls.defaults import *
from myste.views import hello, home
from django.views.static import *
from django.conf import settings
urlpatterns = patterns('',
('^home/$', home)
)
This is the views
def home(request):
return render_to_response('home.html', locals(),context_instance=RequestContext(request))
And finally this is the template (home.html)
url: {{ STATIC_URL }}
Oh, and I'm not sure what I should put in my TEMPLATE_CONTEXT_PROCESSORS but this is it so far.
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
)
And this is the output I get when running the server
url:
I know there might be some huge mistakes in these codes, but that's because I've been reading different sources for different django versions. And yes, I've read the documentations but as I said it didn't help me that much.
You don't seem to have read the instructions at all. The two important things to do are 1) ensure the static processor is in TEMPLATE_CONTEXT_PROCESSORS and 2) define some URLs to actually serve your static files in development.
None of this has "changed in the latest version". There were some improvements in the previous version, 1.3, but the basic principle is the same.
STATIC_URL isn't in your local scope, so passing through locals() as your dictionary isn't going to help.
def home(request):
return render_to_response('home.html', {'STATIC_URL': settings.STATIC_URL},context_instance=RequestContext(request))
or you can use the new static tag available in 1.4 and avoid this particular problem in the template:
{% load static from staticfiles %}
url: {% static "/" %}
'django.core.context_processors.media',
'django.core.context_processors.static',
Those should both be in your TEMPLATE_CONTEXT_PROCESSORS as per this. This makes the STATIC_URL available in all contexts that use request context. If you really read the docs, and make sure you've set them to 1.4, you'll avoid a lot of these types of questions, and save yourself lots of headaches.
You may want to use render to save yourself some headaches and typing. I usually have just have it swapped out for render_to_request(blah) with render(request, context, template) which in this case would be render(request, locals(), 'home.html').