I am new to flask and am very confused regarding including libraries from external folders into the html template. I know how to include from the static folder, but I want to keep my code and the library files in separate folders. So, my directory structure is something like:
./main_directory
|
|_./Code
| |_./flask_script.py
| |_./static
|
|_./Libraries
I know about the send_from_directory() function but I don't understand exactly how to use it. The most common thing I have seen is:
#app.route('/cdn/<path:filename>')
def custom_static(filename):
return send_from_directory(app.config['CUSTOM_STATIC_PATH'], filename)
Which is from another StackOverflow answer. But here what is cdn in this case? Also, what is the value of app.confg['CUSTOM_STATIC_PATH'] set to? And what all should be done in the HTML template to make this work?
In general serving static files with flask is only good for development. Realistically, when going live it is advised to serve static files otherwise, for example having a web server in front of your app and delegating file serving to it, or putting the files in a file store, like AWS S3.
Regarding your custom_static route, cdn in this case is simply a url prefix (it can be anything), you can then address your static assets from templates like <img src="/cdn/test.jpg">. (The cdn prefix can give you a hint that these files are later moved to a CDN and aren't served by flask in production).
app.config['CUSTOM_STATIC_PATH'] should be set to the absolute path to the directory containing your custom static files.
Related
I'm adding some static files to my Python app on Google app engine. I do it like this, as described here.
app.yaml:
handlers:
- url: /stylesheets
static_dir: stylesheets
I put my files in the subdirectory stylesheets within the my_project_app folder.
How can I get the last modified date of a file in stylesheets?
When you indicate the a file or directory is static by default you can not access it with your application, which means you can't get the modification date. You can think of the static files as being uploaded to a different machine that is configured to to serve static files.
You can upload the file both as a static file and an application resource (or use a symlink), but this means it counts twice against the quota. Recently this has been made easier with the addition of the application_readable option. Setting it to true in app.yaml essentially does the same thing. (see: https://cloud.google.com/appengine/docs/python/config/appconfig#Static_Directory_Handlers ).
Once your application can read the file you can use the standard os library to read the whatever information you need.
Answer is simple make static files accessible that is all.
https://cloud.google.com/appengine/docs/python/config/appconfig#Python_app_yaml_Static_file_handlers
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.
use such code to locate file relative to python file - sometimes you need .. to go up.
os.path.join(os.path.dirname(__file__), 'template', 'list_tbody_part.html')
I'm using Django 1.8 and I want to add a parameter to my static files to cache bust.
This is what I'm doing right now, setting a manual parameter:
<link href="{% static 'css/openprescribing.css' %}?q=0.1.1" rel="stylesheet">
But I feel there must be a better way to update the parameter.
I guess it would be a bit neater to have a setting passed through the template (and that would save having to update it in multiple places).
But what would be really nice is if Django could update it automatically for me.
The notes on django-cachebuster suggest that it's now possible to do this automatically in staticfiles, but I can't find anything in the staticfiles docs about it.
Anyone know a way to do this?
Yes this can be done automatically with contrib.staticfiles. There are two additional provided storage classes which will rename files using a hash. These
are documented here: ManifestStaticFilesStorage and CachedStaticFilesStorage
From the docs:
A subclass of the StaticFilesStorage storage backend which stores the file names it handles by appending the MD5 hash of the file’s content to the filename. For example, the file css/styles.css would also be saved as css/styles.55e7cbb9ba48.css.
The purpose of this storage is to keep serving the old files in case some pages still refer to those files, e.g. because they are cached by you or a 3rd party proxy server. Additionally, it’s very helpful if you want to apply far future Expires headers to the deployed files to speed up the load time for subsequent page visits.
The main difference is
CachedStaticFilesStorage is a similar class like the ManifestStaticFilesStorage class but uses Django’s caching framework for storing the hashed names of processed files instead of a static manifest file called staticfiles.json. This is mostly useful for situations in which you don’t have access to the file system.
To enable them you need to change your STATICFILES_STORAGE setting is set to 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage' or 'django.contrib.staticfiles.storage.CachedStaticFilesStorage'. The file names are only changed when DEBUG=False as it would be in production.
I'm no expert in Caching, but I think letting nginx handle caching might be better than using Django. Django has a lot to handle, so you can let the lightweight static server do that nasty job.
I do not use cloudflare, but I use this line to cache my statics, however, immediately the file changes, Nginx propagates the most recent file (thats the same file):
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 30d;
}
which is a snippet from this gist I'm currently using that conf in production, so I know it works.
One thing I'll point out is, make sure MemCached isn't working and connected to your django as a Caching Backend. I say this, because I have spent many hours in time past hitting my head against the wall, simply because MemCached was caching my page with every content in it for up to 10 minutes.
with this nginx location conf, Whenever I change my .css, or upload a new file (static), the new file immediately takes over, as long as I've python manage.py collectstatic'ed them into the appropriate directory
I stand to be corrected though, if that's not actually the part doing the trick.
Proof that above works with Cache-busting (as you call it)
I went into server
Deleted my static folder (nginx still running) sudo rm -rf static/
Accessed my site
No static loaded
Went back, and python manage.py collectstatic
Accessed my site again. Statics loaded
No browser hard refresh was used. No nginx reload|restart whatever was used.
Nginx is smart enough to cache your statics, but reload the static when the file is new and serve it.
If you use a CDN, cache busting becomes more complex. If you just want to bust the cache for a specific image, just create a simple tag that does the trick....
import time
from django import template
register = template.Library()
#register.simple_tag()
def cache_bust():
return int(time.time())
Then in your template just do something like this...
{% load cache_app %}
<img src="/captcha/?cache_bust={% cache_bust %}" class="captcha"/>
And you have cache busting the simple way.
I created a small Flask app for the purpose of processing and presenting data for my local consumption on my local machine. My Flask app processes data in a subfolder and then opens a webpage to display the processed data. Everything looks great except that images are not being served. For example the resulting HTMl source will have something like:
<img src="/Users/username/Desktop/datafolder/pics/pic1.png" alt="pic1">
however there will be no image. The paths are correct so I am guessing it has to do with how images are passed, or not passed, to Flask in the render_template. Perhaps there is a way to specify a media directory as I see in this django post?
Any suggestions on how I might be able to include images would be very welcome.
best regards,
zach cp
Edit: As mentioned in the answers and comments, all static files must be in the designated static directory. My use of the "file://" construct triggered the browser to give an error message:
"Not allowed to load local resource: file:///Users/username/Desktop/datafolder/pics/pic1.png"
which is why I could not see the image. I could use any of the solutions below that result in the images I want to have served in the designated static folder.
The Flask application defaults the files where it attempts to serve static files as the "static" path in the root directory for the application. Thus, if you run your program in...
C:\Users\username\Desktop\MyApp
the static folder will be
C:\Users\username\Desktop\MyApp\Static
Thus, when attempting to serve
/Users/username/Desktop/datafolder/pics/pic1.png
the file Flask will try to serve will actually be...
C:\Users\username\Desktop\MyApp\Static\Users\username\Desktop\datafolder\pics\pic1.png
This probably isn't right.
Therefore, you can do a few things:
Change the files that are being processed to the "static" folder of where you Flask app is running from, and make the HTML src value relative to that directory
Set the static_folder parameter on the Flask constructor. This allows you to set specifically where the static files will be served from.
app = Flask(static_folder='C:\\Some\\Directory')
As some comments have suggested, change to using the file:// type. If it doesn't work, then post what you're trying, because it should work :)
Well,you'd better take a look at this: http://flask.pocoo.org/docs/quickstart/#static-files
What you need to do:
cd path/to/your/flask/app
mkdir static
mv /Users/username/Desktop/datafolder/pics/pic1.png /static
use <img src="/static/pic1.png" alt="pic1"> in your template.
The Flask application defaults the files where it attempts to serve static files as the "static" path in the root directory for the application.
Create Static folder & paste the images in that & give the path as \Static\Img.png
I am writing a web-app in web.py (a rewrite/extension of mongs) which I want to function both as a standalone application, and as a sub-app that requests can be forwarded to. The issue that I am having is that when it is used as a sub-app, static files cannot easily be served from its own static directory. Since I intend to distribute this (and not require users to combine the files into their project's static directory) I want the directory structure to be:
app_that_is_using_mongs (not mine)
static (which holds the app's static files - also not mine)
mongs (my subapp)
main.py (the code for mongs)
view (holds templates)
static (the static folder for mongs)
main.py (the code for the app that is using mongs)
...so that the entire mongs directory is separated from whatever app is using it.
I have considered a few possibilities for getting this to work:
Using a request handler that reads and outputs the files from the static directory, like:
cwd = os.path.dirname(__file__) + '/' # get current working directory
class Static:
def GET(self, filename):
"""searches for and returns a requested static file or 404s out"""
try:
return open(cwd + 'static/' + filename, 'r').read()
except:
web.application.notfound(app) # file not found
I am not sure about the performance of this solution for large files, and it seems like this should be something web.py can do on its own.
Adding another static directory by accessing the cherry.py staticdir tool through web.py... I'm not sure how to do something like this (interacting directly with the server that web.py is running on), and I don't think it would still work if I switched to a Gunicorn server (or any server but cherry.py).
Fixing the way that web.py handles static files to make it more extendable... If there is no other way, then rewriting this portion of web.py and maybe getting it pushed into the main repo is probably the best way.
So, what is the best way to do this?
In web.py the static assets aren't served through the application router. Instead the http server has a check weather the request url starts with /static. This means that weather you have a sub-application or not, the /static/... maps directly to the static directory in the root application.
Your first idea of building a static class will definitely work, but you are right that there is a definite performance implication - though, you'd have to benchmark it to really know how bad it is.
Another option, which is operationally worse, but is a temporary fix is to create a soft-link from the static directory of the parent app, into the sub-application's static directory. i.e.
parent_app/
static/
sub_app/ -> parent_app/sub_app/static/sub_app
...
sub_app/
static/
sub_app/
...
Then, when you want to access a static asset from sub_app, you would hit a url like: /static/sub_app/asset. Since this url starts with /static, it will get caught by the http server and redirect to the static directory, following the soft link, and resolves to the actual asset. Because of the sub_app directory, this solution will work when running the sub_app directly, or running the parent_app. You will have to setup this soft link on every server you deploy to, and for every development environment, which makes this less than ideal.
I can't, for the life of me, get Django to find my JavaScript files! I am trying to plug in a custom widget to the admin page, like so:
class MarkItUpWidget(forms.Textarea):
class Media:
js = (
'js/jquery.js',
'js/markitup/jquery.markitup.js',
'js/markitup/sets/markdown/set.js',
'js/markitup.init.js',
)
css = {
'screen': (
'js/markitup/skins/simple/style.css',
'js/markitup/sets/markdown/style.css',
)
}
However, when this code is inserted on my admin page, all of the links are broken, I can't get to any of my JavaScript files. My settings file looks like this: http://pastebin.com/qFVqUXyG
Is there something I am doing wrong? I'm somewhat new to Django.
I guess you're using django-admin runserver to test your website. In that case, have a look at "How to serve static files" (but don't ignore the big fat disclaimer).
Once you're ready to deploy, this chapter contains all the information (provided you go the standard route of Apache/mod_wsgi)
I don't know what the "django way" to include js files is, but I just use a simple regular include in the template, its great since you can dynamically generate the location / filename for these.. oh and if you are using django's test server I don't know how to get it to recognize these or if it even can but all you need is to run an apache server on your local machine and then put the files in the localhost directory and you can include them through localhost by including their full path in the template (i.e., http://localhost/myfiledirectory/myfile.js), also something I do is use amazon s3 to host files since you then get a url for them on there (not that you asked about this but its a quick way to host files if you don't have apache running locally)
Basically, my understanding of Django is that it works differently than a PHP framework, for example, as the files for Django don't sit (or don't need to at least) in the web path (i.e. they do not need to be accessible through the host path but can be anywhere on the machine) this is good for providing extra security, etc but it also means, that to give files a url to download them they need to be in the web hosting path, others may know how to make django do this directly but my quick and dirty method of putting them on the localhost path will work if thats all you're after.