Flask Blueprints cant override static path - python

I am trying to use Flask Blueprints to serve a multipage webapp.
Webapp structure:
Landing page html->login->Vuejs SPA
Flask structure:
app/
client/
dist/
static/
js/
css/
vue_index.html
client.py
main/
main.py
static/
index.html
__init__.py
__init_.py
app.register_blueprint(main_bp)
app.register_blueprint(client_bp)
client.py
client_bp = Blueprint('client', __name__,
url_prefix='/client',
static_url_path='/client/static',
static_folder='dist/static',
template_folder='dist',
)
#client_bp.route('/')
def client():
dist_dir = current_app.config['DIST_DIR'] #full path to dist folder
entry = os.path.join(dist_dir, 'vue_index.html')
return send_file(entry)
vue_index.html
<!DOCTYPE html><html>...<script src=/static/js/index.js></script></body></html>
Then I run the app and redirect to host:port/client the vue_index.html is found but the .js files referred to in the file cant be found.
However when I move the js/ folder from app/client/dist/static to app/static then the vue_index.html file can locate the js code ok.
So it is evident that the blueprint is not overriding the static path of the flask app. Any idea on how to debug the static paths / fix this?

I got this working by putting all flask static files and templates in a new dist/ folder and adding all the vuejs files into this folder eg
webapp/
dist/
js/ (vuejs files)
css/ (vuejs and flask landing page .css)
index.html (vuejs entry)
other.html (flask misc webpage)
Then to run the app:
app = Flask(__name__,
static_folder='./dist',
template_folder='./dist',
static_url_path='')
Its not ideal (I wanted to keep to vuejs files in a dist on its own and have static and template folders but just couldn't get it to work)

Replace send_file to render_template: https://flask.palletsprojects.com/en/1.1.x/quickstart/#rendering-templates
from flask import render_template
# .....
#client_bp.route('/')
def client():
return render_template('vue_index.html')
For client_bp use static_url_path='static', because in case of /client/static you will create an extra nesting
Update your webpack config to change public URL path to your JS file with /client namespace:
<!DOCTYPE html><html>...<script src=/client/static/js/index.js></script></body></html>
Anyway I recommend you to use different non-nested folders for static files and templates

Related

Unable to find flask template [duplicate]

I am trying to render the file home.html. The file exists in my project, but I keep getting jinja2.exceptions.TemplateNotFound: home.html when I try to render it. Why can't Flask find my template?
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def home():
return render_template('home.html')
/myproject
app.py
home.html
You must create your template files in the correct location; in the templates subdirectory next to the python module (== the module where you create your Flask app).
The error indicates that there is no home.html file in the templates/ directory. Make sure you created that directory in the same directory as your python module, and that you did in fact put a home.html file in that subdirectory. If your app is a package, the templates folder should be created inside the package.
myproject/
app.py
templates/
home.html
myproject/
mypackage/
__init__.py
templates/
home.html
Alternatively, if you named your templates folder something other than templates and don't want to rename it to the default, you can tell Flask to use that other directory.
app = Flask(__name__, template_folder='template') # still relative to module
You can ask Flask to explain how it tried to find a given template, by setting the EXPLAIN_TEMPLATE_LOADING option to True. For every template loaded, you'll get a report logged to the Flask app.logger, at level INFO.
This is what it looks like when a search is successful; in this example the foo/bar.html template extends the base.html template, so there are two searches:
[2019-06-15 16:03:39,197] INFO in debughelpers: Locating template "foo/bar.html":
1: trying loader of application "flaskpackagename"
class: jinja2.loaders.FileSystemLoader
encoding: 'utf-8'
followlinks: False
searchpath:
- /.../project/flaskpackagename/templates
-> found ('/.../project/flaskpackagename/templates/foo/bar.html')
[2019-06-15 16:03:39,203] INFO in debughelpers: Locating template "base.html":
1: trying loader of application "flaskpackagename"
class: jinja2.loaders.FileSystemLoader
encoding: 'utf-8'
followlinks: False
searchpath:
- /.../project/flaskpackagename/templates
-> found ('/.../project/flaskpackagename/templates/base.html')
Blueprints can register their own template directories too, but this is not a requirement if you are using blueprints to make it easier to split a larger project across logical units. The main Flask app template directory is always searched first even when using additional paths per blueprint.
I think Flask uses the directory template by default. So your code should be like this
suppose this is your hello.py
from flask import Flask,render_template
app=Flask(__name__,template_folder='template')
#app.route("/")
def home():
return render_template('home.html')
#app.route("/about/")
def about():
return render_template('about.html')
if __name__=="__main__":
app.run(debug=True)
And you work space structure like
project/
hello.py
template/
home.html
about.html
static/
js/
main.js
css/
main.css
also you have create two html files with name of home.html and about.html and put those files in templates folder.
If you must use a customized project directory structure (other than the accepted answer project structure),
we have the option to tell flask to look in the appropriate level of the directory hierarchy.
for example..
app = Flask(__name__, template_folder='../templates')
app = Flask(__name__, template_folder='../templates', static_folder='../static')
Starting with ../ moves one directory backwards and starts there.
Starting with ../../ moves two directories backwards and starts there (and so on...).
Within a sub-directory...
template_folder='templates/some_template'
I don't know why, but I had to use the following folder structure instead. I put "templates" one level up.
project/
app/
hello.py
static/
main.css
templates/
home.html
venv/
This probably indicates a misconfiguration elsewhere, but I couldn't figure out what that was and this worked.
If you run your code from an installed package, make sure template files are present in directory <python root>/lib/site-packages/your-package/templates.
Some details:
In my case I was trying to run examples of project flask_simple_ui and jinja would always say
jinja2.exceptions.TemplateNotFound: form.html
The trick was that sample program would import installed package flask_simple_ui. And ninja being used from inside that package is using as root directory for lookup the package path, in my case ...python/lib/site-packages/flask_simple_ui, instead of os.getcwd() as one would expect.
To my bad luck, setup.py has a bug and doesn't copy any html files, including the missing form.html. Once I fixed setup.py, the problem with TemplateNotFound vanished.
I hope it helps someone.
Check that:
the template file has the right name
the template file is in a subdirectory called templates
the name you pass to render_template is relative to the template directory (index.html would be directly in the templates directory, auth/login.html would be under the auth directory in the templates directory.)
you either do not have a subdirectory with the same name as your app, or the templates directory is inside that subdir.
If that doesn't work, turn on debugging (app.debug = True) which might help figure out what's wrong.
I had the same error turns out the only thing i did wrong was to name my 'templates' folder,'template' without 's'.
After changing that it worked fine,dont know why its a thing but it is.
You need to put all you .html files in the template folder next to your python module. And if there are any images that you are using in your html files then you need put all your files in the folder named static
In the following Structure
project/
hello.py
static/
image.jpg
style.css
templates/
homepage.html
virtual/
filename.json
When render_template() function is used it tries to search for template in the folder called templates and it throws error jinja2.exceptions.TemplateNotFound when :
the file does not exist or
the templates folder does not exist
Create a folder with name templates in the same directory where the python file is located and place the html file created in the templates folder.
Another alternative is to set the root_path which fixes the problem both for templates and static folders.
root_path = Path(sys.executable).parent if getattr(sys, 'frozen', False) else Path(__file__).parent
app = Flask(__name__.split('.')[0], root_path=root_path)
If you render templates directly via Jinja2, then you write:
ENV = jinja2.Environment(loader=jinja2.FileSystemLoader(str(root_path / 'templates')))
template = ENV.get_template(your_template_name)
After lots of work around, I got solution from this post only,
Link to the solution post
Add full path to template_folder parameter
app = Flask(__name__,
template_folder='/home/project/templates/'
)
My problem was that the file I was referencing from inside my home.html was a .j2 instead of a .html, and when I changed it back jinja could read it.
Stupid error but it might help someone.
Another explanation I've figured out for myself
When you create the Flask application, the folder where templates is looked for is the folder of the application according to name you've provided to Flask constructor:
app = Flask(__name__)
The __name__ here is the name of the module where application is running. So the appropriate folder will become the root one for folders search.
projects/
yourproject/
app/
templates/
So if you provide instead some random name the root folder for the search will be current folder.

CSS not recognized when served with FastAPI

I have a FastAPI app built and an index, css and js file that work when opened directly, but I can't get the css file to show up when being served with FastAPI. I've tried troubleshooting in case the problem is a CORS issue, I've tried re-arranging the files so as to be in the same or different directories (and re-specifying the href path accordingly) but nothing has worked. This is my directory at this point:
working_directory
└── app
|__ index.html
├── style.css
└── main.js
With the app home route set up like so:
file_path = "index.html"
#app.get("/")
async def home():
return FileResponse(file_path)
Would I need to also provide the path to the css file within the file_path variable? The formats I've tried haven't worked thus far and errors with FastAPI aren't as well documented as with Flask or Django, for example.
My error looks like this:
GET http://localhost:8000/style.css net::ERR_ABORTED 404 (Not Found)
How would I get the web app to recognize my style.css file?
You need to actually serve the static files. Below's an example doing so with FastAPI. In a 'real world' scenario you would probably leave serving these files to a reverse proxy, like nginx.
Consider the following structure;
src
app/main.py
static/css/main.css
templates/index.html
main.py
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from pathlib import Path
app = FastAPI()
app.mount(
"/static",
StaticFiles(directory=Path(__file__).parent.parent.absolute() / "static"),
name="static",
)
templates = Jinja2Templates(directory="templates")
#app.get("/")
async def root(request: Request):
return templates.TemplateResponse(
"index.html", {"request": request}
)
index.html
...
<link href="{{ url_for('static', path='/css/main.css') }}" rel="stylesheet">
...

How to load templates from Flask extension

I'm developing a flask extension following this tutorial. The part of my extension are also templates. I want, by default, to use templates from flask extension unless user overrides them in a main flask application. The problem is that by default template path points to main_flask_app/templates. How to go over it? Thanks a lot.
The layout of your app, and separately your extension, should look like this:
myapp_project/
myapp/
__init__.py
models.py
...
static/
templates/
index.html
...
myext/
mypage.html # overrides default from ext
myext_project/
myext/
__init__.py
...
templates/
myext/
mypage.html # the default template from ext
...
Notice how the directory structure is the same. Adding a template with the same path to the app overrides the default on that path in the extension.
Your extension will make these templates available by registering a blueprint with the app. The blueprint should be set up to use the templates folder.
from flask import Blueprint
bp = Blueprint('myext', __name__, template_folder='templates')
class MyExt(object):
...
def init_app(self, app):
...
app.register_blueprint(bp)
...

send_static_file not picking up from static folder at root in Blueprint

From the views.py inside my blueprint, im trying to use the send_static_file to deliver an index.html and just cant get it to work
I have a blueprint called main which I initialize as such in the __init__.py under the blueprint folder mod_main
from flask import Blueprint
mod_main = Blueprint('main',name,static_folder='/static', static_url_path='/static')
from . import views
In my main app initialization in the __init__.py under the root app folder
app = Flask(__name__)
from .mod_main import mod_main as main_blueprint
app.register_blueprint(main_blueprint,url_prefix='/main')
Under the views.py file in the blueprint main (mod_main folder)
#mod_main.route('/')
def index():
return mod_main.send_static_file('index.html')
But it keeps resolving to 404 Not found. Any clue how i can serve the index.html that is under the static folder in the root app folder (I can get it to work if i create a static folder inside the blueprint. But i would like to deliver it from the root app)
Heres the structure with the essential files
app
|
-- mod_main/
|
-- views.py
-- __init__.py
-- __init__.py
-- static /
|
-- index.html
You've told the blueprint to find the static files in /static, or, a folder called static in the root of your file system. Assuming you don't want to change it to static and move the folder into mod_main, there are a couple of different approaches you can take.
If you want to make the distinction between static files for the app and static files for the blueprint, you can serve the file through the current app.
# mod_main/views.py
from flask import current_app
from . import mod_main
#mod_main.route('/')
def index():
return current_app.send_static_file('index.html')
If, however, you intend to use the existing static as your only static folder, you need to update your blueprint to use this folder.
# mod_main/__init__.py
import os
from flask import Blueprint
static_folder = os.path.join(os.pardir, 'static')
mod_main = Blueprint(
'main', __name__, static_folder=static_folder, static_url_path='/static')
from . import views

How to use packaged assets with Flask-Assets

How can I bundle assets using Flask-Assets that exist outside of Flasks default static/ directory?
I have npm install downloading assets into bower_components/
I have other javascripts that exist in javascripts/
I am using Flasks app factory pattern, and no matter how I've tried configuring Flask-Assets - I cannot get around the assets instance not bound to an application, and no application in current context exception.
Any help would be appreciated, especially if you can just give me an example on how to manage raw + packaged assets outside your apps static/ directory :P
app structure
app/
static/
__init__.py
assets.py
javascripts/
app.js
bower_components/
jquery.js
jquery,pjax,js
app/assets.py
from flask.ext.assets import Bundle, Environment
js = Bundle(
'bower_components/jquery.js',
'bower_components/jquery.pjax.js',
'javascripts/app.js'
filters='jsmin',
output='static/packed.js'
)
assets = Environment()
assets.register('js_all', js)
app/init.py
from flask import Flask
from app.assets import assets
app = Flask(__name__)
assets.init_app(app)
I checked Flask-Assets source and found this in the docstring of FlaskResolver class:
If a Environment.load_path is set, it is used to look up source files, replacing the Flask system. Blueprint prefixes are no longer resolved.
So you need to do the following in app/init.py:
from os.path import abspath, join
app = Flask(__name__)
assets.load_path = abspath(join(app.root_path, '..'))
assets.init_app(app)

Categories