I've made a website using Flask and I have no problems getting things to work properly on the built-in development server. I've also been able to get things running on my production server under mod_wgsi. However, I host my static media from a static/CGI/PHP-5.2 application and I can't get Flask to 'see' it without manually changing all the urls in my html files.
The problem seems to be that the basic Flask setup expects static files to be within the flask application. See here for details. Essentially, I think I need to change the url of 'static' portion of the following one liner:
<link rel="stylesheet" href="{{url_for('static', filename='css/print.css')}}" type="text/css" media="print"/>
It looks like I can change this in init.py, instructions here, but defining the static_path as follows doesn't seem to work.
app = Flask(__name__, static_path = '/web_media')
To be clear, if I manually define my url like this:
<link rel="stylesheet" href="/web_media/css/print.css" type="text/css" media="print"/>
everything works fine. Any help would be greatly appreciated.
Override static_folder instead.
app = Flask(__name__, static_folder = '/web_media')
If this is a production set up Flask should not be serving your static content; the web server (nginx, apache, cherokee, etc...) should be handling that as it is more efficient at handling those types of operations than the python process. From the sounds of it (based on the mod_wsgi reference) you are using apache, so this is how you could alter your config file to serve static content from static/CGI/PHP-5.2 using apache.
Assuming "web_media" is a directory under the somewhat fictitious /var/www/static/CGI/PHP-5.2 directory and contains your css/js/etc. assets. In your config file, within the area where you configure this app add something along the lines of.
Alias /web_media/ /var/www/static/CGI/PHP-5.2/web_media/
<Directory /var/www/static/CGI/PHP-5.2/web_media>
Order deny,allow
Allow from all
</Directory>
It's been a while since I used/configured apache, so no guarantees that the above will work perfectly the first time. But the main point is, use the webserver to handle the static media.
For production environment you should serve your static files via http server (e.g. nginx/apache). See answer of Philip Southam above.
Nonetheless, there are times when you use werkzeug server (e.g. dev/testing). In that case, there are 2 keyword arguments to look at:
static_folder: physical location on the file system. If it is relative path than it is relative to the project root directory.
static_url_path: this is the url lookup path for static content.
For example, if I have a static file located at /path/to/static/files/myfile.jpg, with /path/to/static/files as static file root and you want to access it via http://example.com/mystatic/myfile.jpg. I will do the following:
from flask import Flask
app_name = __name__
app = Flask(app_name, static_folder='/path/to/static/files', static_url_path='/mystatic')
Assuming you are using flask version 0.7 or above (currently 0.11.1)
Related
I have HTML/JS/CSS files provided by a third party (whom I have no control over) that serves as a single page app that communicates with a backend built with Django and django-rest-framework.
I'm wanting to host this on Heroku and thus these static assets are being served by Django. These files contains relative paths to each other. For example, the index.html contains:
<link rel="stylesheet" type="text/css" media="screen" href="styles/css/bootstrap.min.css">
Which leads to a 404 because styles/css/bootstrap.min.css is not routed by django.
The only way I know of to serve the index.html from my domain root www.domain.com is with an url config like:
url(r'^$', TemplateView.as_view(template_name='index.html'), name='home'),
...even though it's not really a template, it's just plain HTML.
The problem arises from the fact that all the urls in the other assets are relative to this index.html and of course Django doesn't work like that. If I was developing this front-end application I'd be using the static template tag and one of the various ways to get urls to javascript.
I don't mind switching from Heroku to another PaaS if they offer a solution to this problem, but manually editing all these files does not sound like a fun job...especially considering the fact that I'll be receiving updates to these files going forward.
I think the way to solve this on a regular old server would be to configure the web server to resolve these urls correctly, but that option doesn't seem to be available on Heroku.
Here's how to set up Django to serve your static files and index.html on / while still having the possibility to use Django views for the admin dashboard, registration etc.
from django.conf.urls import include, url
from django.contrib import admin
from django.contrib.staticfiles.views import serve
from django.views.generic import RedirectView
admin.autodiscover()
urlpatterns = [
# / routes to index.html
url(r'^$', serve,
kwargs={'path': 'index.html'}),
# static files (*.css, *.js, *.jpg etc.) served on /
# (assuming Django uses /static/ and /media/ for static/media urls)
url(r'^(?!/?static/)(?!/?media/)(?P<path>.*\..*)$',
RedirectView.as_view(url='/static/%(path)s', permanent=False)),
# other views still work too
url(r'^admin/', include(admin.site.urls)),
]
I specify urlpatterns as a list, as Django 1.10 requires. The redirects are not permanent by default since 1.9, so you need to explicitly set permanent=True if you want browsers to cache this, though when debugging I find it better to start with False.
This approach allows you to use something like create-react-app or Yeoman frontend generators that package a built, minified frontend app into a single folder (like dist/). You then e.g. use a script to move that into Django's static files folder (e.g. myproject/static/) and serve it from Heroku.
What Ian wrote about wanting to use something like S3 for your static files stands, but sometimes you just want to start simple with one repository, one Heroku dyno and still be able to use Django + a SPA. Also, using something like WhiteNoise makes serving static files from Python pretty OK and allows you to
later on easily put a CDN in front of your static files.
Note: for user-uploaded files you should still use an outside service like Amazon S3 or Backblaze B2 (which is 4 lines of code to integrate).
Serving Media Files
WhiteNoise is not suitable for serving user-uploaded “media” files. For one thing, as described above, it only checks for static files at startup and so files added after the app starts won’t be seen. More importantly though, serving user-uploaded files from the same domain as your main application is a security risk (this blog post from Google security describes the problem well). And in addition to that, using local disk to store and serve your user media makes it harder to scale your application across multiple machines.
For all these reasons, it’s much better to store files on a separate dedicated storage service and serve them to users from there. The django-storages library provides many options e.g. Amazon S3, Azure Storage, and Rackspace CloudFiles.
Note 2: on production with DEBUG=False there are issues, so check out this WhiteNoise issue for a solution.
Note 3: Turned this answer into a blog post here.
Note 4: since writing this, I've been tweaking the solution more and more for frontend routing, so I ended up releasing a new django-spa package suited for simple serving of single-page apps from Django.
I have a small django app running onn some rootserver. Its using the django integrated dev server. The url is known only to a few people so think thats ok for now. We can access the website by:
http://<ip>:<Port>/main
A colleague has set up a subdomain like shortcut.somedomain.com that points to the above url.
When trying to access the site via that subdomain the view and template are loaded, but it fails loading the static files. Is there any quick fix to make it work?
Can you show us the code that states which are the static files directories and an example where you use a static file in a template?
Is it possible you're loading the static dirs from a wrong path?
Or maybe you use refer to the files incorrectly in the template?
try doing:
my_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
this will get you the project root.
after that(make modifications if your project structure is different):
STATIC_ROOT = os.path.join(my_path, 'static')
and this should work with your STATIC_URL definition
I notice that when I reference my java scripts and static image files from my templates, they show up in development, but not from the production server. From development, I access them as such:
<img src="/my_proj/media/css/images/collapsed.png" />
but from production, I have to remove the project directory:
<img src="/media/css/images/collapsed.png" />
I'm assuming I'm doing something wrong with regard to serving static media.
I'm caught between a number of seemingly different options for serving static media in Django. On one hand, it's been recommended that I use django-staticfiles to serve media. On the other I see reference to STATIC_ROOT and STATIC_URL in the documentation (with caveats about use in production).
I have small .png files of "plus" and "minus" symbols for use in some of my jQuery scripts. In addition, the scripts themselves need to be referenced.
1) Am I correctly categorizing scripts and site images as static media?
2) What is the best method to access this media (from production)?
You shouldn't keep the URLs hardcoded that way.
If you're running thedev version of Django, you should check this doc.
If you're not, for simplicity, you can use {{ MEDIA_URL }} and configure that variable in your settings for dev and for production.
<img src="{{ MEDIA_URL }}/media/css..." />
Keep in mind that you'll have to use RequestContext, see more here on docs here and here.
Also, you should server all your static files directly trough a proper webserver. You can configure apache or nginx to do that.
Sigh. There is only one way to serve static media in production, and that is to get the webserver - eg Apache - to do it. Django-staticfiles is for development only, and this is clearly stated throughout the documentation.
I'm hosting a site on WebFaction using Django/mod_python/Python2.5. I've recently run into the concept of static files (when setting up my Django admin).
From what I understand, serving static files is simply the idea of telling the server to serve files directly from a specific directory, rather than first routing the request through apache, then mod_python, then django, and finally back to the user. In the case of WebFaction this helps especially since there are two Apache servers that your request must go through (your app's server and the main public server).
Why is it that when I setup Django's static files, it only needs the /media folder in /contrib/admin? Is it just that all of Django's static content is related to the admin panel?
When I want to serve my own static content (images, css, etc.) should I include it in the same /media folder or set up another alias for my own content (/my_media)?
Yes, the static files used by Django are pretty much related to images, javascript and css for the admin. All other static content comes from your application. You can keep both sets (yours and the admin) under the same server. Just set the appropriate folders in the settings file.
http://docs.djangoproject.com/en/dev/ref/settings/#admin-media-prefix
http://docs.djangoproject.com/en/dev/ref/settings/#media-root
http://docs.djangoproject.com/en/dev/ref/settings/#media-url
See this post for a little more information:
Django and Static Files
Django's static files (e.g. js, css, images, etc.) are all in the media folder, and are related to the admin panel.
On WebFaction to save processing power, and more importantly memory, it is better to serve these from your secondary apache server (or even better from nginx or lighttpd) without having to go through mod_python and Django.
I use the following folder setup for my files:
media
css
js
img
etc
admin
css
js
img
See http://forum.webfaction.com/viewtopic.php?id=1981 for how to setup nginx as your secondary server on WebFaction if you are interested.
Let's say you've setup your site using Pylons, Django and most of the site runs fine and according to the framework used. However, what if you had a custom section that was entirely say, composed of flat html files and its own set of images, which you didn't have time to actually incorporate using the framework and were forced to basically support, under the same domain? Should there be some sort of default controller/view that's super bare minimalistic or do frameworks such as these somehow offer support in some smart way?
I realize also that potentially one could setup a new subdomain and reroute it to an entirely different directory, but I'm just curious as to how one would solve this when forced to deal with a framework.
When serving static pages I'd rather avoid having Django or Pylons handle the request, and handle it with the web server only. Using Nginx, you'd use a directive like:
location / {
root /whatever/the/path/is/;
# if the file exists, return it immediately
if (-f $request_filename) {
break;
}
# pass requests to MVC framework
# i.e. proxy to another server on localhost:
proxy_pass http://127.0.0.1:80;
}
For pylons you should be able to drop your static html files in the public directory. If there isn't a controller for a url then I think pylons looks in the public folder next.
For Django, I would serve these in exactly the same way as you serve your static assets - in your site_media directory, along with subdirs for js, css and img, you could have an html directory. Then the URL would just be /site_media/html/whatever.html.
In Django take a look at flatpages. It's part of the django.contrib package and uses flatpages middleware to serve up flat HTML controlled through the admin interface. For basic purposes, serving up additional about pages or the like this should do the trick.
You could also just create an HTML folder and - using mod_python, at least - set no handler for that path in the Apache configuration file (e.g. vhost.conf).