I’m migrating a website from WordPress to Django/Wagtail. I have all the old WP content in my media directory & it’s all being served appropriately.
It would be convenient to map other URLs (specifically /wp-content/) to MEDIA_ROOT, for the sake of old media URLs that were hardcoded in the content.
So for example a migrated asset now available at //example.com/media/uploads/2017/12/IMG_2120.jpg can also be served from //example.com/wp-content/uploads/2017/12/IMG_2120.jpg
I’m sure there’s some obvious way to do this (in urls.py?) but totally drawing a blank.
I'm sure you already know that static/media files should be served using a frontend server (like Nginx), because it's been mentioned at so many places in the docs.
So, if Django doesn't serve the files, why does it need the MEDIA_ROOT and MEDIA_URL settings?
MEDIA_ROOT is the place where Django stores the images/files you upload.
MEDIA_URL is used by Django to generate file urls. For example, if MEDIA_URL = '/media/', then if you do {{ image.url }}, Django will generate a url like this - /media/image.jpg.
But Django doesn't serve the files. Your frontend server does. So, what you do is, you configure your frontend server like this:
if request path starts with /media/:
map it to <media directory>
Basically, you're telling your frontend server to serve content from the <media directory> for every request that starts with /media/. This way, a request starting with /media/ never actually reaches your Django app, because your server is taking care of them.
What I mean by all this is that you can configure your frontend server to map /wp-content/uploads/ to your <media directory> and it will serve the files.
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 django project which is making use of django-rest-framework to provide an api for an angular client.
The entire angular app is developed separately to the django project, and doesn't make use of any django templates or suchlike.
Eventually the angular app will be served as a static asset via nginx or something along those lines.
However, during development, I would like the django development server to serve the angular app.
The issue I have is that none of the static assets in index.html are prefixed with STATIC_URL or a similar static prefix which django can look for.
Attempting to serve all non-api routes as static files as such:
urlpatterns += static(r'', document_root=settings.ANGULAR_APP_ROOT)
gives an exception
Empty static prefix not permitted
I know that in nodejs express server you can use something like:
app.use(express.static(path.join(config.root, 'app')));
which works seamlessly. I guess it searches for any paths in the configured folder and if any match the requested url, serves them.
I do not want to force django specific code/prefixes into the angular app (ala STATIC_URL etc)
What I'm looking for is some middleware which will offer a fallback route for anything unmatched by the existing urlpatterns and search a filesystem path for a matching asset and serve it if found.
Is it possible to get the static assets served like this with the django development server?
I currently have a dotcloud app that uses django to serve everything. It works great, however, we recently had our site redone in angular.js, and I don't want to use django to serve the actual html pages (I want to just use nginx for that), but I want django to serve some links for the API we built for the angular code to use.
Is it possible for me, in the same app, to configure nginx to serve some static files for particular urls, and have it send other urls for django to serve?
I want nginx to serve my index.html page is a request comes in to wwww.example.com, but if a request for example.com/api/login/ comes in, I want that to be handled by django. Is this possible?
Yes, you can do what you are looking for, you just need to add an nginx.conf to your project and then specify which urls you want nginx to serve and which ones you want django to serve, by default they will all go to django, so you just need to specify which ones you want to be served by nginx.
Here is a link to the documentation: http://docs.dotcloud.com/0.4/guides/nginx/
Link to the nginx documentation on location blocks: http://wiki.nginx.org/HttpCoreModule#location
Here is an example for serving static files from nginx, you can use this as a guide to do what you need.
location /media/ {
root /home/dotcloud/data ;
}
location /static/ {
root /home/dotcloud/volatile ;
}
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.