Flask unable to resolve static files - python

I am trying to write a simple API using Flask. I am following Miguel Grinberg's blog.
I have a use-case where I am trying to serve a static page. I am unable to serve the static webpage.
Here is my app.py
from flask import Flask, request, abort, render_template
app = Flask(__name__)
#app.route('/sample/application/', methods=['GET'])
def static_website():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
And following is my directory layout:
flask_application/
- app.py
- static/
- index.html
- cs/
- app.css
- bootstrap.css
- js/
- jquery.js
- images/
- logo.png
Before anyone marks this as a duplicate, I have gone through the following posts and it has not resolved my issue.
Unable to serve css, js and image files
No response + question for templating
Again related to templating
There are other questions but no ones gives a concrete solution to resolve css, js files in static pages.
The server created by Flask is unable to pickup the js, css files.
Also, I am avoiding templating because this the only use-case I have and I am pretty sure, I am not going to add any other pages or make it more complex.

The template needs to be in a folder called templates. So the correct solution should be
flask_application/
- templates/
- index.html
You can read the documentation for the render_template method.

If you don't care about renderung a template, you can just send the static file on your route. This way you can just leave everything in the static directory.
app.send_static_file('index.html')
Just remember the rest of the assets will need to be referenced as /static/<asset>, ie <script src="/static/js/jquery.js></script>

Related

Using CSS Templates with Flask: Overriding "static system"

I'm just starting out with Flask, and I was wondering what the best method for
dealing with how flask deals with static files when trying to use a premade CSS template.
Basically, I have downloaded a CSS template that I liked off the internet, but when if I simply drag the files into my flask application folder the CSS, JS, and image files do not work since they are not located in the static folder.
But if I move all the static files into the static folder, then I have to go through all the code and change the link urls, which is very time consuming.
The CSS Template I am using has an index.html that uses links like
<link rel = "stylesheet" href = "css/style.css" >
I have set both the static_folder = ""
and the static_url_path = "" in my flask app and I have moved the css, js, and image folders from the downloaded template into the base folder for the application, but the links are still not working.
Is there a better way to deal with using premade CSS templates with flask? Can I override the need to put css and js and image files in the static folder somehow? Thanks for your help!
(Sorry for opening this old post, but I'm on a badge hunt :])
There are several possible solutions, but the one I would recommend is to move the file style.css to folder <server_root>/static/css/.
Then create the flask app like app = Flask(__name__, static_url_path=''), what means that it still serves static files from the static/ folder, but on path / (so <server_root>/static/css/style.css is served on /css/style.css).
With this setup, your links href="/css/style.css" will work.
However, it's strongly recommended to use flask.url_for('endpoint', param='value') instead of /endpoint/url/value both in code and templates (surrounded with {{ ... }}) for all URLs - static files ('static', filename='css/style.css') and your own endpoints. So if your endpoint looks like this,
#app.route('/some/path/<variable>')
def some_endpoint(variable):
# do something and return response...
... you can use url_for('some_endpoint, variable='something') no matter what the actual URL (/some/path/something/ in this case) is. (Tested python 3.6.7; flask 1.0.2)

Where to locate user data in Flask application?

I have a flask application where a user's profile image is stored. I originally stored the images in the static directory like so:
application.py
templates/
static/userdata/user/icon.png
Though I don't think this is a good idea because it is not good practice to modify the static directory in production.
I tried making a new userdata folder at root like so:
application.py
templates/
static/
userdata/user/icon.png
Though when I try to access the file with Jinja and HTML,
<img src="/userdata/user/icon.png">
the image does not show. Why is this?
Thanks, in advance.
Use the url_for function
.html
<img src="{{ url_for('userdata', filename='/user/icon.png')}}">
.py
from flask import send_file
#route('/userdata/<filename:filename>')
def get_user_data_files(filename):
return send_file(app.config['USER_DATA_FOLDER'] + filename)

Serve an external full webpage trough Flask

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.

Google App Engine static file serving conflicts with application

I have a single page app (SPA) that I am running off of Google App Engine (GAE). GAE does three things:
Serve the index.html file
Serve the static files (JS, CSS, etc.)
Serve the dynamic files (images, text, etc. via REST)
I use the following app.yaml configuration.
handlers:
- url: /app
static_dir: app
- url: /.*
script: main.app
My understanding is that this should match any requests going to the /app folder, which would serve my static files. All the REST services and the main index page would then be caught by the /.* and processed by main.py
However, I see the following behavior:
If I remove the /app handler, I can successfully serve the index.html (via Jinja templating) and the REST services (such as localhost/subjects/). However, I cannot see the static files (as expected).
If I add the /app handler, the index.html file does not serve and gives an "Internal Server Error" IOError(errno.EACCES, 'file not accessible', filename). However, when I request a static file such as: "localhost/app/app.js", this succeeds.
Is there something that I am missing here? I do not understand why the two would conflict.
Thank you!
Notes:
Google App Engine 1.8.9, Python 2.7, Developing locally
EDIT:
Here is the Python code I am using to serve the page
path = os.path.join(os.path.dirname(__file__), 'app')
jinja_environment = jinja2.Environment(loader=jinja2.FileSystemLoader(path))
class MainHandler(webapp2.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/html'
template_values = {}
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render(template_values))
My directory structure is as follows:
/
main.py
app.yaml & etc.
app
index.html
app.js
Module A
moduleA.tpl.html
moduleA.js
Edit 2:
I moved index.html to the root directory (/), and then used the following python code:
path = os.path.dirname(__file__)
jinja_environment = jinja2.Environment(loader=jinja2.FileSystemLoader(path))
It (very interestingly) appears that the "double mapping" of the index.html to the Jinja template and to the static directory files caused a problem. I wonder what is the best practice way to do this. I use Jinja for one reason: adding the (GAE generated) login/logout link to the index.html file. Other than that, there is no reason for using it.
Python is by default unable to access files or directories marked as static in App Engine. You can add application_readable: true to your handler mapping to enable this.
Another solution would be to move the index.html away from the static folder since it in fact isn't a static file but instead is a jinja template for Python.
Related question: Read a file on App Engine with Python?
Documentation for application_readable
application_readable
Optional. By default, files declared in static file handlers are uploaded as static data and are only served to end users, they cannot be read by an application. If this field is set to true, the files are also uploaded as code data so your application can read them. Both uploads are charged against your code and static data storage resource quotas.
Ok it might explains scenario #2, how do you access the index.html? If you add /app to the handler and your request url is something like /app/index.html it will serve from the static dir.
On your scenario seems your url does not contain /app, therefore it goes to the 2nd handler rule which is going to main.app.
However since you put the html inside the /app, appengine treats it as static file. If you want to serve the file from jinja template, you should not put it in static_dir
Jinja templates (or Django, Mako etc) has no requirement to be sat in a publicly accessible folder. They are always called via a handler in the application and compiled in the application before serving to the user.
It is common practice to put these in a /templates directory. There is no reference to this directory in app.yaml, it is purely used internally to serve the templates. Check out some of the boilerplate apps in github (search 'gae boilerplate'). This one is minimal and uses Jinja so may be a good example for you https://github.com/SoulAuctioneer/notvanillae

With Flask, how can I serve robots.txt and sitemap.xml as static files? [duplicate]

This question already has answers here:
Static files in Flask - robot.txt, sitemap.xml (mod_wsgi)
(10 answers)
Closed 8 years ago.
I've read on quiet a few places that serving static files should be left to the server, for example in a couple of the answers on this SO question. But I use the OpenShift PaaS, and can't figure out how to modify the .htaccess file there.
I came across this piece of code that serves the sitemap from a template. I did that on my app for both the sitemap, and robots.txt, like so -
#app.route("/sitemap.xml")
def sitemap_xml():
response= make_response(render_template("sitemap.xml"))
response.headers['Content-Type'] = 'application/xml'
return response
#app.route("/robots.txt")
def robots_txt():
return render_template("robots.txt")
Is there any harm in this, or is my approach okay?
Put robots.txt and sitemap.xml into your app's static directory and define this view:
from flask import Flask, request, send_from_directory
#app.route('/robots.txt')
#app.route('/sitemap.xml')
def static_from_root():
return send_from_directory(app.static_folder, request.path[1:])
Flask has built in support for serving static files.
Make a /static directory and put your files there. Then, when you instantiate Flask, specify the static_url_path parameter:
app = Flask(__name__, static_url_path='/')
The default is to serve static files from the /static/ path, but you want them served from / so they are where expected.
See the Flask API Docs for more info.
In addition to overhead and unnecessary code, the problem with your approach is if / when one of the files you want to serve contains something that looks like a template tag to render_template -- you can cause a rendering error. If you were to read the file into memory (once, not inside the method) then use that string as the body of the response without calling render_template, you would at least avoid that problem.
The best way is to set static_url_path to root url
from flask import Flask
app = Flask(__name__, static_folder='static', static_url_path='')

Categories