how to serve generated files via django - django

I am generating tar.gz files with Django and save it to somewhere like /home/foo/foo.tar.gz but I don't know what is a good way to serve these generated files under django view.
I am using return HttpResponseRedirect("/home/foo/foo.tar.gz") but it is actually not a good way to serve tar.gz files because the generated tar.gz file path start from / (root dir) of my linux server instead of a relative path.
Thanks.

Just send it in the response.

If you're not looking to protect with with authentication via Django, you can serve it up with your http server (nginx, lighttpd, apache, etc) - this reduces server impact.

You could define the redirect path relative to MEDIA_ROOT or another setting in settings - and as James says you should definitely consider configuring your http server to handle those files if you haven't already.
# settings.py
TARBALL_ROOT = '/home/foo/tarballs/'
# views.py
import os
from django.conf import settings
def your_view(request):
# do some stuff
filepath = os.path.join(settings.TARBALL_ROOT, 'relative/path/from/media/root'
return HttpResponseRedirect(filepath)

Related

Django deployment variables

I have a development app running locally. I have a production app running on my server. I would like to keep developing locally and push my changes. However, the dev version uses local postgres and the static and media files reside inside the project. The server version the static and media files are in a static public_html directory served by apache. Can I have a local static and media files as well as different postgres credentials on localhost than on the server? How do I accomplish that?
The python-dotenv package is designed specifically for the issue you are running into. Instead of using JSON files it uses .env files which follows the practice of 12 factor apps.
An example would be
settings.py
from dotenv import load_dotenv
load_dotenv()
DEBUG = os.getenv('DEBUG', 1) # with a default value
SECRET_KEY = os.getenv('DJANGO_SECRET_KEY')
DB_USERNAME = os.getenv('DB_USERNAME')
DB_PASSWORD = os.getenv('DB_PASSWORD')
LOGGING_FOLDER = os.getenv('LOGGING_FOLDER')
# Allowed hosts can be stored and split into a list
# Also the name in the separate settings file does not have to match the settings.py variable name
ALLOWED_HOSTS = os.getenv('HOSTS', '').split(' ')
# This will be ['locahost', 'localhost:8000']
# ...
.env
DJANGO_SECRET_KEY=somethingotherthanthis
DB_USERNAME=postgres
DB_PASSWORD=123456
LOGGING_FOLDER=/var/logging/app/
HOSTS=localhost localhost:8000
Of course you don't have to use the external package you can always use the JSON file and only change the following code in your settings. What you will want to be careful of in both circumstances is that the file you are saving your sensitive data and environment specific information (like media folders, logging folders, etc) is not checked into the version control system.
settings.py
import json
with open('settings.json') as fh:
file_settings = json.load(fh)
DEBUG = file_settings.get('DEBUG', 1)
# ...

Use sphinx with Flask and preserve formatting

I generate some Python documentation with Sphinx. If I go to the build/html directory and open index.html directly, I get Sphinx formatting.
If I try to serve the same page Flask with the following code, I get the page but all the Sphinx formatting is gone:
from flask import send_from_directory
#app.route('/help')
def help():
return send_from_directory('/sphinx/build/html', 'index.html')
I am calling Flask directly with app.run in debug mode. This is how I like it. I know how to set it up in Apache but I don't want to run Apache. Is it possible to serve Sphinx inside Flask and still get the formatting, or do I absolutely have to run a web serve like Apache?
Copy your Sphinx documentation folder with generated html files /sphinx/build under the static folder ./static/sphinx/build.
Then use Jinja to link it:
Documentation
The resulting url on your local server will look similar to this:
http://127.0.0.1:5000/static/sphinx/build/html/index.html
When your app is deployed, replace the new directory with a symbolic link, so needn't copy the /sphinx/build folder every time the documentation is built.

Using Django static() to generate audio files' URLs in production

I'm trying to get my Django app to play audio files (supposedly) uploaded by users via a form. Said files are tied to a model :
# models.py
class Doc(models.Model):
# ...
tape = models.FileField()
The uploading and saving parts are working fine, and the files are stored where they should be :
- djangoproject
|
- docapp
|
- media <- here
So, in order to get where I want, I added these two lines to the settings.py file MEDIA_ROOT = os.path.join(BASE_DIR, 'docapp/media/') and MEDIA_URL = 'docapp/media/'.
I hoped to be able to link to the audio files thus:
# templates/docapp/index.html
...
<audio src='{{ doc.tape.url }}' controls></audio>
Unfortunately, this wasn't working because the link generated by doc.tap.url (http://localhost/docapp/media/filename.aac) was returning a 404 error.
After a lot of googling I found this answer, which I happily copy-pasted into my app ... and it worked. This is the code in question :
# urls.py
from django.conf import settings
from django.conf.urls.static import static
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
The problem is that I'm not comfortable with inserting code in my apps that I don't understand. I did some research about the static() function and all I could get is this :
Helper function to return a URL pattern for serving files in debug mode
Does this mean that the static function should not be used in production? If so, what should I be using in production? And what exactly does it do?
EDIT To be clear, the generated URL after injecting the solution is the same as the one generated without it. Yet, it only works when the static() function is present.
EDIT 2 I forgot to mention that the 404 errors persisted even after I chmoded the media folder to allow others to read-access it.
Thanks in advance!
You shouldn't do anything. No errors no problem. The docs write about development server and serving static files AND that it is for development only. In a production environment you configure your server (Apache, NGNIX or third party like S3) to serve the files. That's all.
Try to configure media files and access the file via it's url. If it works, try the {{ doc.tape.url }} template tag.
In your development environment your media may live in /media/ (route and directory). While on production it may be something like media.example.com. Running Django with the settings for that environment will change all static/media domains and paths to their correct locations.
You may split settings file into a settings file for each environment (production, acceptance, development). Like this:
project/
settings/
__init__.py
base.py
local.py
staging.py
test.py
production.py
You can run your project with a specific env: ./manage.py runserver --settings=project.settings.development. Do not repeat yourself and put development specific settings in development.py and from base import * so that base.py contains the default settings.
This project and settings layout is taken from the book Two Scoops of Django. It is just an example. Adjust to your own needs.
Yes, django.conf.urls.static.static is only for development and not for production. For production, you should just need to configure your MEDIA_URL and MEDIA_ROOT settings and have your webserver serve the MEDIA_ROOT directory in the MEDIA_URL path.
Basically adding that in the URL urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) will make the media files in the URL existing. Try removing that and visit your media file in the URL and you will receive a 404 not found. It's very similar to the concept that you are inserting a view for rendering the media files

Django, boto, S3 and easy_thumbnails not working in production environment

I'm using Django, django-storages with S3 (boto) in combination with easy-thumbnails. On my local machine, everything works as expected: if the thumbnail doesn't exists, it gets created and upload to S3 and saves in the easy-thumbnails database tables. But the problem is, when I push the code to my production server, it doesn't work, easy-thumbnails output an empty image SRC.
What I already noticed is that when I create the thumbnails on my local machine, the easy-thumbnail path uses backward slashes and my Linux server needs forwards slashes. If I change the slashes in the database, the thumbnails are showed on my Linux machine, but it is still not able to generate thumbnails on the Linux (production) machine.
The simple django-storages test fails:
>>> import django
>>> from django.core.files.storage import default_storage
>>> file = default_storage.open('storage_test', 'w')
Output:
django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_FILE_STORAGE, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.
If I do:
>>> from base.settings import staging
>>> from django.conf import settings
>>> settings.configure(staging)
This works (I have a settings directory with 4 settings files: base.py, staging.py, development.py and production.py)
It seems that on my production server, the config file isn't loaded properly (however the rest of the website works fine). If I add THUMBNAIL_DEBUG = True to my settings file, but easy-thumbnails' debugging still doesn't work (it does work on my local machine).
What can be te problem? I've been debugging for 10+ hours already.
Try refactoring your settings to use a more object-oriented structure. A good example is outlined by [David Cramer from Disqus:
http://justcramer.com/2011/01/13/settings-in-django/
You'll put any server-specific settings in a local_settings.py file, and you can store a stripped-down version as example_local_settings.py within your repository.
You can still use separate settings files if you have a lot of settings specific to a staging or review server, but you wouldn't want to store complete database credentials in a code repo, so you'll have to customize the local_settings.py anyways. You can define which settings to include by adding imports at the top of local_settings.py:
from project.conf.settings.dev import *
Then, you can set your DJANGO_SETTINGS_MODULE to always point to the same place. This would be instead of calling settings.configure() as outlined in the Django docs:
https://docs.djangoproject.com/en/dev/topics/settings/#either-configure-or-django-settings-module-is-required
And that way, you know that your settings on your production server will definitely be imported, since local_settings.py is always imported.
first try to use:
python manage.py shell --settings=settings/staging
to load shell with correct settings file and then try to debug
For some reason, S3 and easy thumbnails in the templating language didn't seem to get along with each other ... some path problem which probably could be solved at some point.
My solution (read: workaround) was to move the thumbnail generation into the model inside the image field itseld, for example:
avatar = ThumbnailerImageField(upload_to = avatar_file_name, resize_source=dict(size=(125, 125), crop="smart"), blank = True)
For the sake of completeness:
def avatar_file_name(instance, filename):
path = "%s/avatar.%s" % (str(instance.user.username), filename.split('.')[1])
if os.path.exists(settings.MEDIA_ROOT + path):
os.remove(settings.MEDIA_ROOT + path)
return path

Why does Django fail to make directories and open files on production server?

Bringing up a Django site on a production Linux server using Apache with mod_python, I'm running the following code for a file upload:
from django.conf import settings
import os
# ...
upload_base_dir = "upload"
file_pointer = files['file']
file_path = os.path.join(settings.ROOT_SITE_DIR, upload_base_dir, event_name)
if not os.path.exists(file_path):
os.makedirs(file_path)
file = open(file_path + '/' + file_name, 'wb+')
for chunk in file_pointer.chunks():
file.write(chunk)
file.close()
The file_path is an absolute path to the file. I've done a little debugging to find that if the file_path doesn't exist, os.makedirs() fails (500 error returned to requester). If the file_path does exist, the file open fails. I've ensured that directory permissions are permissive enough.
The code works when I am running the Django development server. I've used this code before, and it works in other sites. I'm pretty sure the Apache configuration is the same for relevant settings.
Should be a simple fix, so this is driving me crazy. Does anyone have pointers for other things I should check? Can I rule out Apache as part of the issue?
Does os.path.join always leave you a trailing slash on file_path? Because if not, then your open(file_path+file_name) won't have one between them. Try os.path.join on them.
Dunno why it would be different from your development server though...
Looks like the Apache threads didn't have access to the files because they were spawned under a user (www-data) that wasn't part of the group that owns the directories. Hopefully this can help someone else save time down the road.