I've set up a Blueprint in my Flask application, but I can't seem to get my static folder to work. I keep getting 404 errors when it tries to reach them:
127.0.0.1 - - [11/Sep/2014 15:14:20] "GET /static/js/bootstrap.min.js HTTP/1.1" 404 -
127.0.0.1 - - [11/Sep/2014 15:14:20] "GET /static/static/css/bootstrap.min.css HTTP/1.1" 404 -
The css one also appends static twice. The JS has the correct /static but doesn't seem to work. Right now, my static folder is in the blueprint root path (app/dashboard). I tried putting it into app/static but I get the same exact errors.
I have the following set up:
app/dashboard/__init__.py:
from flask import Blueprint
dashboard = Blueprint('dashboard', __name__, template_folder='templates', static_folder='static')
from application.dashboard import controllers
app/__init__.py:
# Blueprints
from flask import Blueprint
from application.dashboard import dashboard
app.register_blueprint(dashboard)
In app/templates/layout.html, I have a line that references two static files as follows:
<link rel="stylesheet" type="text/css" href="{{ url_for('dashboard.static', filename='css/bootstrap.min.css') }}">
<script src="{{ url_for('dashboard.static', filename='js/bootstrap.min.js') }}"></script>
My app/dashboard/static directory:
$ tree application/dashboard/static/
application/dashboard/static/
├── css
│ ├── bootstrap-theme.css
│ ├── bootstrap-theme.css.map
│ ├── bootstrap-theme.min.css
│ ├── bootstrap.css
│ ├── bootstrap.css.map
│ └── bootstrap.min.css
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ └── glyphicons-halflings-regular.woff
└── js
├── bootstrap.js
└── bootstrap.min.js
Any idea what is going on here? How can I structure my Blueprint properly? I've followed the instructions on the Flask documentation and I get this error.
Thank you.
Look like you have issue with two same routes for application and blueprint. See my another answer part 3.
Your application route /static/<path:path> to .static endpoint.
Your blueprint route /static/<path:path> to dashboard.static endpoint, because you do not have url_prefix when register blueprint and have /static - static folder prefix.
So you can use one of next solutions:
use only application static folder.
set url_prefix when register blueprint.
use another static folder prefix for blueprint.
disable application static folder app = Flask(__name__, static_folder=None).
use hacks with static endpoint descriptor.
You need to add URL prefix for your blueprint, like so
app.register_blueprint(dashboard, url_prefix='/dashboard')
I had the same problem. Solution was to go to the __init__.py file for the Blueprint, then add static_folder="static" inside the statement defining the blueprint:
from flask import Blueprint
main = Blueprint('main', __name__ ,static_folder = "static")
from . import routes
Since the app is actually running as the Blueprint, main here, this tells it to look for the static folder inside the main package. It doesn't work if you add this to the __init__.py script for the app (ask me how I know this...)
Why not use nginx? It's faster in terms of performance and you don't have to write code to serve up static content.
Related
i'm creating some unit tests and i'm facing this issue
FAILED test_views_home.py::test_index -
jinja2.exceptions.TemplateNotFound: index.html
this is part of my testing code:
templates = Jinja2Templates('templates')
def test_index():
#router.get('/', include_in_schema=False)
async def index(request: Request):
return templates.TemplateResponse('index.html', {'request': request})
client = TestClient(router)
response = client.get("/")
assert response.status_code == 200
assert '<!DOCTYPE html>' in response.text
and this is my folder structure:
root/
├── views/
│ ├── index.py
├── templates/
│ ├── index.html
├── tests/
│ ├── test_sorullo.py
i got:
FAILED test_views_home.py::test_index -
jinja2.exceptions.TemplateNotFound: index.html
I'm guessing i'm putting wrong
templates = Jinja2Templates('templates')
but i couldn't figure it out. I didn't find anything similar searching. What i'm doing wrong?
thanks!
The error says that Jinja2 template engine is unable to find the specified template file. Check your template directory and make sure the file index.html is present.
The template directory is set to "templates". So the Jinja2 engine will look for the templates files in the directory named "templates" in the same directory of your code file, If the template files are located in a different directory, you can specify the full path to the directory instead of just the directory name.
Try to add the full path of template directory. If it solves you can correct the directory path.
This question already has answers here:
How to serve static files in Flask
(24 answers)
Closed 1 year ago.
This post was edited and submitted for review 1 year ago and failed to reopen the post:
Original close reason(s) were not resolved
Edit:
I resolved this however cannot add an answer as the question is locked.
When passing image paths to a html file that is called using flask, flask assumes a folder exists called static in the dir from where the app is called. In my case this was test_uploads/app. So to call my image, I had to place a folder called static in this location, with my image file in it:
test_uploads
├── app
│ ├─ templates
│ │ └─ image.html
│ ├─ static
│ │ └─ image.jpg
│ ├─ __init__.py
│ └─ routes.py
├── config.py
└── main.py
My call from the html file then took the following structure:
<!-- image.html -->
<!DOCTYPE html>
<html>
<head>
<title>View Stock</title>
</head>
<body>
<img src="static/{{ image }}">
</body>
Et voila, the image renders.
This file location can be manipulated using the app.config.static_folder, and app.config.static_url_path attributes to suit your own location however.
This seems to be a common issue, and I've looked at a few questions on here, but I just can't get it to work.
I have stripped my whole app back to this most basic functionality, and still can't make the web page show my image.
All I get is the error icon and a 404 error in console. The path that is given in the error is the correct path to my image though, so I am even more confused.
Whe
I have the following file structure, and am trying to show image.jpg on a web page:
test_uploads
├── app
│ ├─ templates
│ │ └─ image.html
│ ├─ __init__.py
│ └─ routes.py
├── cover_images
│ └─ image.jpg
├── config.py
└── main.py
<!-- image.html -->
<!DOCTYPE html>
<html>
<head>
<title>View Stock</title>
</head>
<body>
<img src="{{ image }}">
</body>
# __init__.py
from config import Config
from flask import Flask
app = Flask(__name__)
app.config.from_object(Config)
from app import routes, models
# config.py
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config():
UPLOAD_FOLDER = os.path.join(basedir, 'cover_images')
# main.py
from app import app
# routes.py
from app import app
from flask import render_template
import os
#app.route('/check')
def image_check():
image_path = os.path.join(app.config['UPLOAD_FOLDER'], 'image.jpg')
print(image_path)
return render_template('image.html', image = image_path)
And the terminal output:
127.0.0.1 - - [19/Nov/2021 10:51:57] "GET /check HTTP/1.1" 200 -
127.0.0.1 - - [19/Nov/2021 10:51:57] "GET /Users/<me>/Downloads/test_uploads/cover_images/image.jpg HTTP/1.1" 404 -
Try adding ./ before the rest of it.
Should be as this
“../image.jpg”
I have built a flask app that I have been starting from an if __name__ == '__main__': block, as I saw in a tutorial. When the time came to get the app to launch from wsgi for production use, I had to remove the port and host options from app.run(), and make changes to the structure of the launching code that I am not too sure about. I am now adding test cases, which adds more ways to launch and access the app (with app.test_client(), with app.test_request_context(), and who knows what else.) What is the right / recommended way to structure the code that creates and launches the application, so that it behaves correctly (and consistently) when launched stand-alone, from wsgi, and for testing?
My current structure is as follows:
def create_app():
"""
Create and initialize our app. Does not call its run() method
"""
app = Flask(__name__)
some_initialization(app, "config_file.json")
return app
app = create_app()
...
# Services decorated with #app.route(...)
...
if __name__ == "__main__":
# The options break wsgi, I had to use `run()`
app.run(host="0.0.0.0", port=5555)
To be clear, I have already gotten wsgi and tests to work, so this question is not about how to do that; it is about the recommended way to organize the state-creating steps so that the result behaves as a module, the app object can be created as many times as necessary, service parameters like port and server can be set, etc. What should my code outline actually look like?
In addition to the launch flag issue, the current code creates an app object (once) as a side effect of importing; I could create more with create_app() but from mycode import app will retrieve the shared object... and I wonder about all those decorators that decorated the original object.
I have looked at the documentation, but the examples are simplified, and the full docs present so many alternative scenarios that I cannot figure out the code structure that the creators of Flask envisioned. I expect this is a simple and it must have a well-supported code pattern; so what is it?
Disclaimer While this isn't the only struture for Flask, this has best suited my needs and is inspired from the Flask officials docs of
using a Factory
Pattern
Project Structure
Following the structure from the Documentation
/home/user/Projects/flask-tutorial
├── flaskr/
│ ├── __init__.py
│ ├── db.py
│ ├── schema.sql
│ ├── auth.py
│ ├── blog.py
│ ├── templates/
│ │ ├── base.html
│ │ ├── auth/
│ │ │ ├── login.html
│ │ │ └── register.html
│ │ └── blog/
│ │ ├── create.html
│ │ ├── index.html
│ │ └── update.html
│ └── static/
│ └── style.css
├── tests/
│ ├── conftest.py
│ ├── data.sql
│ ├── test_factory.py
│ ├── test_db.py
│ ├── test_auth.py
│ └── test_blog.py
├── venv/
├── setup.py
└── MANIFEST.in
flaskr/, a Python package containing your application code and files.
flaskr will contain the factory to generate flask app instances that can be used by WGSI servers and will work with tests, orms (for migrations) etc.
flaskr/__init__.py contains the factory method
The Factory
The factory is aimed at configuring and creating a Flask app. This means you need to pass all required configurations in one of the many ways accepted by Flask
The dev Flask server expects the function create_app() to be present in the package __init__.py file. But when using a production server like those listed in docs you can pass the name of the function to call.
A sample from the documentation:
# flaskr/__init__.py
import os
from flask import Flask
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
)
if test_config is None:
# load the instance config, if it exists, when not testing
app.config.from_pyfile('config.py', silent=True)
else:
# load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
# a simple page that says hello
#app.route('/hello')
def hello():
return 'Hello, World!'
return app
when running a dev flask server, set environment variables as described
$ export FLASK_APP=flaskr
$ export FLASK_ENV=development
$ flask run
The Routes
A Flask app may have multiple modules that require the App object for functioning, like #app.route as you mentioned in the comments. To handle this gracefully we can make use of Blueprints. This allows us to keep the routes in a differnt file and register them in create_app()
from flask import Blueprint, render_template, abort
from jinja2 import TemplateNotFound
simple_page = Blueprint('simple_page', __name__,
template_folder='templates')
#simple_page.route('/', defaults={'page': 'index'})
#simple_page.route('/<page>')
def show(page):
try:
return render_template(f'pages/{page}.html')
except TemplateNotFound:
abort(404)
and we can modify the create_app() to register blueprint as follows:
def create_app(test_config=None):
app = Flask(__name__, instance_relative_config=True)
# configure the app
.
.
.
from yourapplication.simple_page import simple_page
app.register_blueprint(simple_page)
return app
You will need to locally import the blueprint to avoid circular imports. But this is not graceful when having many blueprints. Hence we can create an init_blueprints(app) function in the blueprints package like
# flaskr/blueprints/__init__.py
from flaskr.blueprints.simple_page import simple_page
def init_blueprints(app):
with app.app_context():
app.register_blueprint(simple_page)
and modify create_app() as
from flaskr.blueprints import init_blueprints
def create_app(test_config=None):
app = Flask(__name__, instance_relative_config=True)
# configure the app
.
.
.
init_blueprints(app)
return app
this way your factory does not get cluttered with blueprints. And you can handle the registration of blueprints inside the blueprint package as per your choice. This also avoids circular imports.
Other Extensions
Most common flask extensions support the factory pattern that allows you to create an object of an extension and then call obj.init_app(app) to initialize it with Flask App. Takeing Marshmallow here as an exmaple, but it applies to all. Modify create_app() as so -
ma = Marshmallow()
def create_app(test_config=None):
app = Flask(__name__, instance_relative_config=True)
# configure the app
.
.
.
init_blueprints(app)
ma.init_app(app)
return app
you can now import ma from flaskr in which ever file required.
Production Server
As mentioned initialially, the production WSGI serevrs will call the create_app() to create instances of Flask.
using gunicorn as an example, but all supported WSGI servers can be used.
$ gunicorn "flaskr:create_app()"
You can pass configurations as per gunicorn docs, and the same can be achieved within a script too.
What I did was:
class App:
def __init__(self):
# Various other initialization (e.g. logging, config, ...)
...
self.webapp = self._start_webapp(self.app_name, self.app_port, self.log)
pass
def _start_webapp(self, app_name: str, app_port: Optional[int], log: logging):
log.info('Running webapp...')
webapp = Flask(app_name)
# other flask related code
...
webapp.run(debug=False, host='0.0.0.0', port=app_port)
return webapp
pass
if __name__ == '__main__':
app = App()
This way you can add optional parameters to the init to override during tests or override via config change and even create additional types of endpoints in the same application, if you need.
I'm using Jinja2 in Flask. I want to render a template from a string. I tried the following 2 methods:
rtemplate = jinja2.Environment().from_string(myString)
data = rtemplate.render(**data)
and
rtemplate = jinja2.Template(myString)
data = rtemplate.render(**data)
However both methods return:
TypeError: no loader for this environment specified
I checked the manual and this url: https://gist.github.com/wrunk/1317933
However nowhere is specified to select a loader when using a string.
You can provide loader in Environment from that list
from jinja2 import Environment, BaseLoader
rtemplate = Environment(loader=BaseLoader).from_string(myString)
data = rtemplate.render(**data)
Edit: The problem was with myString, it has {% include 'test.html' %} and Jinja2 has no idea where to get template from.
UPDATE
As #iver56 kindly noted, it's better to:
rtemplate = Environment(loader=BaseLoader()).from_string(myString)
When I came to this question, I wanted FileSystemLoader:
from jinja2 import Environment, FileSystemLoader
with open("templates/some_template.html") as f:
template_str = f.read()
template = Environment(loader=FileSystemLoader("templates/")).from_string(template_str)
html_str = template.render(default_start_page_lanes=default_start_page_lanes,
**data)
I tried using the FileSystemLoader, but that didn't immediately work for me. My code was all in a module (a subdirectory with an __init__.py file), so I was able to use PackageLoader instead. The Jinja documentation calls this "the simplest way" to configure templates:
my-proj
├── Pipfile
├── Pipfile.lock
└── app
├── __init__.py
├── app.py
├── constants.py
└── templates
├── base.html.jinja
└── macros.html.jinja
from jinja2 import Environment, PackageLoader
def generate_html(my_list):
env = Environment(loader=PackageLoader("app"))
template = env.get_template("base.html.jinja")
return template.render({ "stuff": my_list })
I have a blueprint with its own template folder. There is also a base layout template in the "top" templates folder. I want to access this template from a blueprint template. I tried the following but got a "Template Not Found" error.
{% extends "../../../../../templates/layout.j2" %}
The package looks like this:
__init__.py
├── modules
│ └── citrixlb
│ ├── citrixlb.py
│ └── templates
└── templates
└── layout.j2
I set up the blueprint's template_folder:
citrix = Blueprint('citrix', __name__, template_folder='templates', url_prefix='/citrix')
What is the correct way to reference a template from another template directory?
Flask's Jinja loader flattens the global folder and all blueprint folders into a common tree, prioritizing the global folder. So simply refer to the template as if it was at the top level location.
{% extends "layout.j2" %}
Note that by using the "j2" extension rather than ".html", you've probably inadvertently disabled automatic escaping. It is recommended that you use the ".html" extension for html templates.