Image Files Uploading Example on a Shared Host
We start from where we left off (Need a minimal Django file upload example). The difference is we do it on a shared host not a on a local host.
With small changes, the source code we used on a local host in previous chapter, we'll deploy it to a shared host running Django 1.6.5:
$ python -c "import django; print(django.get_version())" 1.6.5
The changes are:
- db: from sqlite to mysql
- urls.py
- Images files will be saved into media/documents which is a sub-diretory of the document root directory (www/dj). Note that we set:
MEDIA_ROOT = '/home2/bogotob1/www/dj/media/' MEDIA_URL = 'http://www.bogotobogo.com/dj/media/'
in settings.py.
- .htaccess
We need to create .htaccess file under the root directory of our Django project which is ~/public_html/djangoproject:
$ cd ~/public_html/djangoproject
Add the following to .htaccess:
AddHandler fcgid-script .fcgi RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ mysite.fcgi/$1 [QSA,L]
- djangoproject.fcgi
~/public_html/djangoproject/djangoproject.fcgi file should look like this:
#!/home/directory/bin/python import sys, os sys.path.insert(0, "/home/directory/python") sys.path.insert(13, "/home/directory/djangoproject") os.environ['DJANGO_SETTINGS_MODULE'] = 'djangoproject.settings' from django.core.servers.fastcgi import runfastcgi runfastcgi(method="threaded", daemonize="false")
- project: djangoproject
- app: myapp
- document root: www/dj
When we do upload an image file, it will be saved into ~/www/dj/media/documents. Note that we created the two directories (media and documents) before the upload.
We need to set the database we're going to use. In this example for shared host, we'll use mysql:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'bogotob1_djforum', 'USER': 'bogotob1_djforum', 'PASSWORD': 'my_password', 'HOST': 'localhost', # Or an IP Address that your DB is hosted on 'PORT': '3306', } }
To upload files and to serve them, we want to specify where Django stores uploaded files and from what URL Django serves them via two variables in settings.py: MEDIA_ROOT and MEDIA_URL. They are by default empty:
# Absolute filesystem path to the directory that will hold user-uploaded files. # Example: "/home2/media/media.lawrence.com/media/" MEDIA_ROOT = '/home2/bogotob1/www/dj/media/' # URL that handles the media served from MEDIA_ROOT. Make sure to use a # trailing slash. # Examples: "http://media.lawrence.com/media/", "http://example.com/media/" MEDIA_URL = 'http://www.bogotobogo.com/dj/media/'
Then, we also need to add myapp to INSTALLED_APPS:
INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', 'myapp', )
Now we need a model with a FileField. This field stores files e.g. to media/documents/2014/07/06/ based on current date and MEDIA_ROOT. See FileField reference:
class FileField([upload_to=None, max_length=100, **options])
Our code:
from django.db import models class Document(models.Model): docfile = models.FileField(upload_to='documents/%Y/%m/%d')
If our MEDIA_ROOT is set to /home2/bogotob1/www/dj/media/, and upload_to is set to documents/%Y/%m/%d. The %Y/%m/%d part of upload_to is strftime() formatting; %Y is the four-digit year, %m is the two-digit month and %d is the two-digit day. If we upload a file on July 06, 2014, it will be saved in the directory /home2/bogotob1/www/dj/media/documents/2014/07/06
To handle upload properly, we need a form. This form has only one field because of our minimal approach. See Form FileField reference for details:
class FileField(**kwargs)
Our code:
from django import forms class DocumentForm(forms.Form): docfile = forms.FileField( label='Select a file', )
This defines a Form class with a single field (docfile) of FileField.
Our code:
from django.shortcuts import render_to_response from django.template import RequestContext from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse from myproject.myapp.models import Document from myproject.myapp.forms import DocumentForm def list(request): # Handle file upload if request.method == 'POST': form = DocumentForm(request.POST, request.FILES) if form.is_valid(): newdoc = Document(docfile = request.FILES['docfile']) newdoc.save() # Redirect to the document list after POST return HttpResponseRedirect(reverse('myproject.myapp.views.list')) else: form = DocumentForm() # A empty, unbound form # Load documents for the list page documents = Document.objects.all() # Render list page with the documents and the form return render_to_response( 'myapp/list.html', {'documents': documents, 'form': form}, context_instance=RequestContext(request) ) def index(request): return render_to_response('myapp/index.html')
request.FILES['docfile'] can be saved to models.FileField. The model's save() handles the storing of the file to the filesystem automatically.
"Django does not serve MEDIA_ROOT by default. That would be dangerous in production environment. But in development stage, we could cut short. Pay attention to the last line. That line enables Django to serve files from MEDIA_URL. This works only in development stage." - from Need a minimal Django file upload example.
from django.conf.urls import patterns, include, url from django.conf import settings from django.conf.urls.static import static from django.views.generic import RedirectView from django.contrib import admin # admin.autodiscover() urlpatterns = patterns('', (r'^myapp/', include('myapp.urls')), )
See django.conf.urls.static.static and Django: how do you serve media / stylesheets and link to them within templates.
from django.conf.urls import patterns, include, url urlpatterns = patterns('myapp.views', url(r'^$', 'list', name='list'), url(r'^list/$', 'list', name='list'), )
In this section, we have a template for the list and an upload form. The form must have enctype attribute set to multipart/form-data and method set to post to make upload to Django possible. See File Uploads documentation for details.
The FileField has many attributes that can be used in templates. E.g. {{ document.docfile.url }} and {{ document.docfile.name }} as in the template. See more about these in Using files in models article and The File object documentation.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Minimal Django File Upload Example</title> </head> <body> <!-- List of uploaded documents --> {% if documents %} <ul> {% for document in documents %} <li><a href="{{ document.docfile.url }}">{{ document.docfile.name }} <img src="{{ document.docfile.url }}" alt="{{ document.docfile.name }}"> </a></li> {% endfor %} </ul> {% else %} <p>No documents.</p> {% endif %} <!-- Upload form. Note enctype attribute! --> <form action="{% url "list" %}" method="post" enctype="multipart/form-data"> {% csrf_token %} <p>{{ form.non_field_errors }}</p> <p>{{ form.docfile.label_tag }} </p> <p> {{ form.docfile.errors }} {{ form.docfile }} </p> <p><input type="submit" value="Upload" /></p> </form> </body> </html>
In ~/djangoproject directory:
$ python manage.py syncdb
Here is the archive of the source code:
myapp.tar.gz.
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization