How to use django-cumulus for serving Static files? - django

I'm trying to use django-cumulus for serving files off Rackspace CloudFiles. I'm currently only trying it on my local dev server, using Django 1.4.2.
I can use cumulus's syncstatic management command to upload all my static assets successfully, but I can't seem to display them on my site with the same settings.
If my relevant settings are:
STATIC_URL = '/static/'
CUMULUS = {
'USERNAME': 'myusername',
'API_KEY': 'myapikey',
'CONTAINER': 'mycontainername',
'STATIC_CONTAINER': 'mycontainername',
}
DEFAULT_FILE_STORAGE = 'cumulus.storage.CloudFilesStorage'
STATICFILES_STORAGE = 'cumulus.storage.CloudFilesStaticStorage'
then when I run syncstatic all my apps' static files are uploaded into /mycontainername/static/, as I'd expect. But when I load a page in admin it ignores STATIC_URL and tries to serve assets from URLs like http://uniquekey....r82.cf2.rackcdn.com/path/to/file.css rather than http://uniquekey....r82.cf2.rackcdn.com/static/path/to/file.css.
Also, I can't see how to have my public (non-admin) pages use the static files on CloudFiles, rather than serving them from a local /static/ directory.
Have I missed some crucial setting, or am I doing something else wrong?

I had the same problem. What i did was to
git clone https://github.com/richleland/django-cumulus.git
edit context_processors.py
from django.conf import settings
from cumulus.storage import CloudFilesStorage
def cdn_url(request):
"""
A context processor to expose the full cdn url in templates.
"""
cloudfiles_storage = CloudFilesStorage()
static_url = '/'
container_url = cloudfiles_storage._get_container_url()
cdn_url = container_url + static_url
print {'CDN_URL': cdn_url}
return {'CDN_URL': cdn_url}
Once you are done, install it with sudo python setup.py install
Do note that context_processors.py from django cumulus is actually quite slow

Related

How To Serve media Files In Production

I have a Django project which sends automated e-mails with attached pdfs to users. At the moment I just have a normal /media/ folder with the pdf in it which the code points to. This works in development but throws a server error in production.
My question is how do I server media files in production? I have read a lot about it but can't find exactly what I'm after.
I use collectstatic in my production environment which works for static files, I'd expect something similar for media files.
urls
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('page.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
settings
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static_files')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, "static_media")
views.py (that sends the file)
file_path = os.path.join(settings.STATIC_ROOT+'\\pdf\\free_pdf.pdf')
...
msg.attach_file(file_path)
passenger.wsgi
import os
import sys
sys.path.append(os.getcwd())
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
import django.core.handlers.wsgi
from django.core.wsgi import get_wsgi_application
from whitenoise import WhiteNoise
SCRIPT_NAME = os.getcwd()
SCRIPT_NAME = '' #solution for damn link problem
class PassengerPathInfoFix(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
from urllib.parse import unquote
environ['SCRIPT_NAME'] = SCRIPT_NAME
request_uri = unquote(environ['REQUEST_URI'])
script_name = unquote(environ.get('SCRIPT_NAME', ''))
offset = request_uri.startswith(script_name) and len(environ['SCRIPT_NAME']) or 0
environ['PATH_INFO'] = request_uri[offset:].split('?', 1)[0]
return self.app(environ, start_response)
application = get_wsgi_application()
application = PassengerPathInfoFix(application)
application = WhiteNoise(application, root='/home/mysite/mysite/static_files')
(this code is from when I abandoned the media folder and was trying to just serve it with my static files)
My proj structure:
|project
|__app
|__static
| |__app
| |__style.css
|__media
| |__app
| |__pdfToBeSent
|__static_files (generated by collectstatic)
|__media_files (i created this)
collectstatic also doesn't copy my projects media files into media_files, I have been copying them in there myself (unsure about this).
I have also tried moving the media file to every possible location in my project
I am also serving my static files with whitenoise.
Thank you.
Since I was in a similar situation (on the same hosting, A2Hosting), I will try to share my understanding of the problem and the solution I opted for.
Pardon me if I may seem presumptuous in this presentation, I'm simply trying to retrace all the points that represent the flow of thoughts that led me to this solution.
A small premise: if with "media files" you intend multimedial files, such as images and so on, I think you shouldn't use the Django media folder as it's designed to serve files uploaded by the users.
Not knowing if your PDFs are indeed uploaded by some user or not, I'll try to expose my solution anyway.
When in a production environment, Django isn't going to serve static and media files.
For the former I too used WhiteNoise, while for the latter the approach is different (at least on a shared hosting base).
When we set Debug = False in settings.py I suspect that the media folder, created along with the Django project, becomes somewhat unreadable/unaccessible (I cannot tell if by the hand of Django or by the hand of the hosting, or a conjuction of the two).
The official method to handle media files is indeed to rely on an external storage service (like Amazon S3), but this solution isn't suitable for budget limited scenarios.
In my situation, I had the Django app running on a subdomain related to my main domain.
Principal domain: www.mydomain.com
App domain: subdomain.mydomain.com
Leaving the media folder created with the Django project where it was, I created another one in the following unix path:
/home/A2hosting_username/subdomain.mydomain.com/media
Then, in settings.py I changed the MEDIA_ROOT variable from:
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
to:
MEDIA_ROOT = '/home/A2hosting_username/subdomain.mydomain.com/media'
After that, in the model.py class used to define the database and interact with it, I specified the path to the uploaded media (videos, in my case) in this way:
class Video(models.Model):
name = models.CharField(max_length=50)
path = models.FileField(upload_to="../media/videos", null=True, verbose_name="")
Since we don't have access to the Apache config file, it may be useful to edit the .htaccess file (relative to subdomain.mydomain.com) in the following way, to prevent the browser to "time out" when the uploaded file is somewhat heavy:
<ifModule mod_headers.c>
Header set Connection keep-alive
</ifModule>
I hope this can be of any help.

Read static file in view

To integrate Django and Ember, I have decided to serve my Ember SPA in a Django view (avoids CORS issues, only one server for frontend and API, etc). I do it like this:
# urls.py
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^api/', include(api_urls, namespace='api')),
...
url(r'^$', views.emberapp, name='emberapp'),
...
]
# views.py
from django.http import HttpResponse
def emberapp(request):
# The Ember frontend SPA index file
# This only works in development, and is anyway hacky
EMBER_FE_INDEX_HTML = '/absolute/path/to/my/frontend/static/fe-dist/index.html'
template_file = open(EMBER_FE_INDEX_HTML)
html_content = index_file.read()
index_file.close()
return HttpResponse(html_content)
The index.html is part of the static assets. In development this is very easy:
The index.html is directly accessible to the Django application in the file system
I know the absolute path to the index file
But in production things are more complex, because the static assets are not local to the django application, but accessible on Amazon S3. I use django-storages for that.
How can I read the contents of a static file from a view, in a generic way, no matter what backend is used to store/serve the static files?
First, I don't think the way you do it is a good idea.
But, to answer your question: In your settings.py, you likely have defined the directory where Django will collect all static files.
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
So in your view, you just need to fetch the file os.path.join(settings.STATIC_ROOT, 'index.html')
That said, you should serve index.html via the webserver, same as your static/ files, robots.txt, favicon.ico, etc. Not through Django. The webserver is much faster, uses proper caching, and its just one line in your Nginx or Apache settings, instead of an entire view function in Django.
This is my current solution. Works in development, not sure about production yet (it is a pain that you need to commit untested code to verify production-related code in Heroku)
from django.conf import settings
from django.http import HttpResponse
from django.core.files.storage import get_storage_class
FE_INDEX_HTML = 'fe/index.html' # relative to the collectstatic directory
def emberapp(request):
# The Ember frontend SPA index file
# By getting the storage_class like this, we guarantee that this will work
# no matter what backend is used for serving static files
# Which means, this will work both in development and production
# Make sure to run collectstatic (even in development)
# TODO: how to use this in development without being forced to run collectstatic?
storage_class = get_storage_class(settings.STATICFILES_STORAGE)
# TODO: reading from a storage backend can be slow if assets are in a third-party server (like Amazon S3)
# Maybe streaming the static file from the server would be faster?
# No redirect to the Amazon S3 asset, please, since the Ember App needs to
# run from the same URL as the API, otherwise you get CORS issues
with storage_class().open(FE_VWORKS_INDEX_HTML) as index_file:
html_content = index_file.read()
return HttpResponse(html_content)
Or, to reply with an StreamingHttpResponse, which does not force Django to read the whole file in memory (and wait for it to be read):
def emberapp(request):
# The Ember frontend SPA index file
# By getting the storage_class like this, we guarantee that this will work
# no matter what backend is used for serving static files
# Which means, this will work both in development and production
# Make sure to run collectstatic (even in development)
# TODO: how to use this in development without being forced to run collectstatic?
storage_class = get_storage_class(settings.STATICFILES_STORAGE)
index_file = storage_class().open(FE_INDEX_HTML)
return StreamingHttpResponse(index_file)

Django: Static files missing when rendering template

I am using django 1.3 and trying to deploy a django project (client sent) on my dev machine (ubuntu 12.04). The problem is regarding the static files. My directory structure is as follows:
project_name
media
static
css
img
js
settings.py
Here is my settings.py:
ROOT = '/home/user/project_name'
MEDIA_ROOT = '%s/media/' % ROOT
MEDIA_URL = '/media/'
STATIC_ROOT = '%s/static/' % ROOT
STATIC_URL = '/static/'
STATICFILES_DIRS = ()
My site is perfectly deployed but the css, js and imgs are missing. Same is the case for the admin interface. When I use the link http://mysite.com/static/js/some.js it gives a 404.
Help would be appreciated and up-voting an answer is custom.
I think you need to run ./manage.py collectstatic :)
You don't mention configuring your web server to actually serve the static files. You need to point it at the directory that collectstatic put them into.
did you run python manage.py collectstatic ? see here
be careful that in production you should place the static file in a static server. There should be something in the guidelines.
And a little offtopic..
It will be better, to use:
MEDIA_ROOT = os.path.join(os.path.dirname(file),'media').replace('\','/')
STATIC_ROOT = os.path.join(os.path.dirname(file),'static').replace('\','/')
and in main urls.py at development, django webserver only:
urlpatterns = patterns('',
(r'^media/(?P.*)','django.views.static.serve',{'document_root': os.path.join(os.path.dirname(file),'media').replace('\','/') }),
(r'^static/(?P.*)','django.views.static.serve',{'document_root': os.path.join(os.path.dirname(file),'static').replace('\','/')}),
In this way, u dont need collectstatic, ull need it at production server, where u will use nginx or something other to server your static

Adding expire header for Django static files on Heroku

I'm trying to optimize my webpage and am having trouble setting expiration date headers on my static files.
I am running django-1.5, python-2.7.3.
Here's my cache settings in settings.pyso far:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': os.path.join(PROJECT_ROOT, 'cache/'),
}
}
CACHE_MIDDLEWARE_ALIAS = 'default'
CACHE_MIDDLEWARE_SECONDS = 5 * 60
CACHE_MIDDLEWARE_KEY_PREFIX = ''
MIDDLEWARE_CLASSES = (
'django.middleware.cache.UpdateCacheMiddleware',
...
'django.middleware.cache.FetchFromCacheMiddleware',
)
And my static file settings in settings.py:
import os.path
PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
PROJECT_ROOT = os.path.abspath(os.path.join(PROJECT_DIR, '..'))
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'staticfiles/')
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(PROJECT_DIR, 'static'),
)
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
The closest advice I've found was here, but I'm unable to modify the .htaccess files on Heroku.
Any help is greatly appreciated. Thanks!
The django staticfiles app does not provide out of the box support for custom headers. You'll have to hack together your own view to serve up the files and add custom headers to the HttpResponse.
But You should not be serving your static files using Django. This is a terrible idea.
Django is single-threaded, and blocking. So every time you're serving a user a static file, you're literally serving nothing else (including your application code, which is what Django is there for).
Django's staticviews file is insecure, and unstable. The documentation specifically says not to use it in production. So do not use it in production. Ever.
In production you shouldn't serve static files with Django. See the warning boxes on this page: https://docs.djangoproject.com/en/1.4/ref/contrib/staticfiles/#static-file-development-view
In development, Django's contrib.staticfiles app automatically serves staticfiles for you by overwriting the runserver command. This way you can't control the way it serves the static files.
You can prevent the staticfiles app from serving the static files by adding the --nostatic option to the runserver command:
./manage.py runserver --nostatic
Then you can write an url config to manually serve the static files with headers you want:
from functools import wraps
from django.conf import settings
from django.contrib.staticfiles.views import serve as serve_static
from django.conf.urls import patterns, url
urlpatterns = patterns('', )
if settings.DEBUG:
def custom_headers(view_func):
#wraps(view_func)
def wrapper(request, *args, **kwargs):
response = view_func(request, *args, **kwargs)
response['Custom-header'] = 'Awesome'
response['Another-header'] = 'Bad ass'
return response
return wrapper
urlpatterns += patterns('',
url(r'^static/(?P<path>.*)$', custom_headers(serve_static)),
)
If you want your manage.py to have the --nostatic option on by default, you can put this in your manage.py:
if '--nostatic' not in sys.argv:
sys.argv.append('--nostatic')
I think since you are hosting your project on heroku , the generally accepted practice seems to be using S3 for serving static files.
Have a look at this question :
Proper way to handle static files and templates for Django on Heroku
I am not too sure about this but I am sure you should be able to change headers while serving files from S3 atleast this SO question seems to suggest that way
Is it possible to change headers on an S3 object without downloading the entire object?
Hope this helps

STATIC_ROOT in Django on Server

I'm 2hours stuck in a issue about STATIC_URL and STATIC_ROOT when I try to make run the webapp on my server at webfactional.
when I load the webpage all the requests works well, except by the fact that any link with {{ STATIC_URL}} is working or loading.
So a common error that appears on firebug is:
GET http://mydomain/static/extras/h5bp/js/libs/modernizr-2.5.3.min.js 500 (Internal Server Error)
My setup is:
urls.py
I did nothing, and there's nothing about static files.
settings.py
DEBUG = False
STATIC_ROOT = '/home/mydomain/webapps/static_app/'
STATIC_URL = 'http://mydomain/static/'
STATICFILES_DIRS = ()
views.py
view example
#csrf_exempt
def IndexView(request):
try:
request.user.is_authenticated()
except AttributeError:
return render_to_response('index.html',
{'request': request,},
context_instance=RequestContext(request))
return render_to_response('index.html',
{'request': request, 'profile' : request.user},
context_instance=RequestContext(request))
index.html
a part of code not found
<script src="{{ STATIC_URL }}extras/h5bp/js/libs/modernizr-2.5.3.min.js"></script>
well, I follow all the points of:
https://docs.djangoproject.com/en/1.4/howto/static-files/
and this another one:
http://docs.webfaction.com/software/django/getting-started.html
I'm using the correct installed apps, middlewares, template_contexts.
If I'm missing something please help me to figure out.
Thanks in advance!
--edit
I have to say, if I just change the DEBUG = True will works fine.
because on urls.py I have this piece of code:
if settings.DEBUG:
# static files (images, css, javascript, etc.)
urlpatterns += patterns('',
(r'^media/(?P<path>.*)/$', 'django.views.static.serve', {
'document_root': settings.MEDIA_ROOT}))
2 things must happen on a production environent that is not needed in the development environment.
You must run manage.py collectstatic -- this collects all static files into your STATIC_ROOT directory.
You must serve your STATIC_ROOT directory at the STATIC_URL url. How exactly depends on your production setup. This is not even django related; all that matters is that STATIC_ROOT contents are available at STATIC_URL.
Let's say you're using Apache, you'd alias a URL to a directory.
Alias /static/ /path/to/my/static_root/
If you're using nginx, it would be something like
location = /static/ {
alias /path/to/my/static_root/;
}
I just realized you're using webfaction, in which case you set up a static application which literally just serves files at the targeted directories at the URL you define. I'm trying to remember my webfaction login to see the exact procedure, but it shouldn't be difficult to figure out.
Update:
Logged into webfaction; you can create an application that is a symlink. Easy!
Create a symbolic link app that serves /YOUR_STATIC_URL/ and point it to /YOUR_STATIC_ROOT/. Done!