Cannot show image from STATIC_FOLDER in Flask template - python

I set folder for static files like this
app.config['STATIC_FOLDER'] = 'tmp'
In template i use img tag to show an image stored in /tmp:
<img src='IKE2low.jpg' width="200" height="85">
In firebug i see 404 error instead of image. Please tell me what did i do wrong?
Thanks in advance.

I'm not sure what is this STATIC_FOLDER configuration item you are using. Where did you find it?
There are actually two arguments to the Flask class constructor that govern the configuration of static files:
static_folder: defaults to "static". This is the prefix that you have to use in URLs to access the static files.
static_url_path: this is the disk location of the static folder. By default this value is the same as the static_folder setting.
For example, if you use this configuration:
from flask import Flask
app = Flask(__name__, static_url_path = "/tmp", static_folder = "tmp")
Then you can access your images as follows:
<img src='/tmp/IKE2low.jpg' width="200" height="85">
You can also remove the need to have a prefix in the URLs as follows:
from flask import Flask
app = Flask(__name__, static_url_path = "", static_folder = "tmp")
And then you can access your images as:
<img src='/IKE2low.jpg' width="200" height="85">
Note that you still need to have a root /.
But the best way to do this is to not reference image paths explicitly and instead use url_for to generate the correct URLs. If you are using Jinja2 templates that would be:
<img src="{{ url_for('static', filename = 'IKE2low.jpg') }}" width="200" height="85">
This last expression would work regardless of where and how the static files are configured.

Related

Flask 404'ing on static content I have in an assets directory

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.

Flask: serve assets without leading slash using url_for

I'm working on a Flask app that uses url_for to specify the route to some static assets (js, css, etc). Here's an example from one of the templates:
<script src='{{ url_for('static', filename='js/search.js') }}'></script>
When this gets rendered into html, the path looks like this:
<script src='/static/js/search.js'></script>
Is it possible to modify this behavior such that the leading slash is dropped from the rendered script path? The goal is to render the following:
<script src='static/js/search.js'></script>
I'd be very grateful for any insights others can offer on this question!
I was having a similar issue with loading a css file that was on a custom static path.
One fix could be to change the ROOT_DIRECTORY of the application, but this didn't work for my application as I only need to change the static path.
I used a combination of static_folder and static_url_path:
STATIC_URL_PATH = '/your/custom/path/static' # Where the css is stored
STATIC_FOLDER = 'your/custom/path/static'
app = Flask(__name__, static_folder=STATIC_FOLDER,
static_url_path=STATIC_URL_PATH)
As you can see, the main difference is the leading / in the beginning, but this made the app to be able to find the css.

jinja2 link to static files

I am trying to understand how to create a link to static files in jinja2.
Everything I look up relates to Flask whereas I am using just webapp2 at this stage.
My main.py file looks as follows:
import os
import urllib
from google.appengine.api import users
from google.appengine.ext import ndb
import jinja2
import webapp2
JINJA_ENVIRONMENT = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
extensions=['jinja2.ext.autoescape'],
autoescape=True)
class MainPage(webapp2.RequestHandler):
def get(self):
template = JINJA_ENVIRONMENT.get_template('/templates/base.html')
self.response.out.write(template.render())
class ConsultsPage(webapp2.RequestHandler):
def get(self):
template = JINJA_ENVIRONMENT.get_template('/templates/consults.html')
self.response.out.write(template.render())
class CreateConsultPage(webapp2.RequestHandler):
def get(self):
template = JINJA_ENVIRONMENT.get_template('/templates/create-consult.html')
self.response.out.write(template.render())
app = webapp2.WSGIApplication([
('/', MainPage),
('/consults', ConsultsPage),
('/schedule/create-consult', CreateConsultPage)
], debug=True)
My base.html template contains the links to the static files in "/css", "/js" "/images" etc.
When I look at the localhost:8080/ and localhost:8080/consults all the static files are working. Page looks fine.
However the next level in the structure localhost:8080/consults/create-consult is not linking to static files.
When I view source I see that the css link has rendered as localhost:8080/consults/css/style.css , when the actual location is localhost:8080/css/style.css.
I understand I may need to make all links dynamic via some environment variable called uri_for, but I can't find the correct way to implement this.
I tried to replace my css link with
href="{{ uri_for('static', filename='css/screen.css') }}"
I was told by App Engine uri_for not set.
Basically would like to know the correct process for setting uri_for and then how to incorporate it in the paths for my links to static files.
Any help appreciated.
uri_for() is a Flask-specific function; it matches the name static to a route, which in turn then can be used to generate a path (like /static/css/screen.css if the static route is configured to handle /static/<path:filename> urls).
You just need to hardcode the path as /css/screen.css, no need for functions.
Note the leading /; that makes it an absolute path, relative to your current host. For a page at http://localhost:8080/foo/bar, such a path is then prefixed with http://localhost:8080 to form http://localhost:8080/css/screen.css. When you deploy to the app engine, the hostname will be different.
You could store a prefix URL or path in a global, so you can easily swap out the path for a CDN later:
JINJA_ENVIRONMENT.globals['STATIC_PREFIX'] = '/'
and use that in your templates:
<style src="{{ STATIC_PREFIX }}css/screen.css"></style>
You can now alter all such URLs in one place, by setting the STATIC_PREFIX to a different value, including http://somecdn.cdnprovider.tld/prefix/.

Flask not serving image

I have a form where users upload a file and its path is stored in a database and the file is stored in '/static/uploads/images/'.
Now in my templates when I call for that image to be displayed I am doing this: <img src="{{ asset_info.picture_location }}" />
The picture_location is the column where the path is being kept. The asset_info is the model object.
For some reason it is returning a 404 when attempting to retrieve the image:
GET /static/uploads/images/motor.gif HTTP/1.1" 404 -even though that is the correct path and I can see the file in there.
Inspecting the url of the broken image icon on the page shows it is retrieving the correct path from the database: http://localhost:5000/static/uploads/images/motor.gif
The response on the client brower says this:
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
I've googled around quite a bit but have not had any luck. Is there a separate method I'm supposed to call / build to serve images?
This blueprints info: assets_blueprint = Blueprint('assets', __name__, static_folder='/static', template_folder='templates')
Directory is:
app/
assets/
views.py
asset_models.py
asset_forms.py
other_blueprints/
etc.py
static/
uploads/
images/
motor.gif
app.py
config.py
Figured it out. I had manual settings in the blueprint overriding the default root static folder. I took those out and it defaulted back to serving from the default root static folder, then updated my template code to:
<img src="{{ url_for('static', filename=asset_info.picture_location) }}" /> telling it to retrieve the path from the static root folder. I also then had to append my database location formatting by removing the /static/ from the string concatenation because the url_for('static' .... includes that when it generates the url:
Old:
filename_input = str('static/uploads/images/' + str(request.files['photo'].filename))
New:
filename_input = str('uploads/images/' + str(request.files['photo'].filename))

Reference static files in django in .py files ( NOT in templates)

I've been like an hour searching how to reference static files in django, but I only found how to do it in templates.
In my project, I succeeded in referencing static files in my templates, but I DON'T want to do it in templates, I want to do it in my .py files.
I think that i have to import static from somewere, I've tried with this:
from django.templatetags.static import static
from django.conf.urls.static import static
And trying to reference it like this
'<a href=/url> <img src="{{ STATIC_URL }}image.png" ></a>'
I've tried all possible combinations like
{% static image.png %}
{{static image.png}}
and so on...
Thanks!
from django.templatetags.static import static
'<a href=/url> <img src="{0}" ></a>'.format(static("image.png"))
Note that django.templatetags.static is actually a function. The template engine calls that function when you use the template tag.
If you want to find the actual file on disk, you can use the finders class of the staticfiles app:
>>> from django.contrib.staticfiles import finders
>>> finders.find("icons/exclamation.svg")
'C:\\<project folder>\\<project name>\\<app name>\\static\\icons\\exclamation.svg'
Django Docs
You can read django configuration to get STATIC_URL which contains URL base part for static files:
from django.conf import settings
import urlparse
print '' % urlparse.urljoin(settings.STATIC_URL, 'image.png')

Categories