Upload Status mit Django und AJAX anzeigen

Auf einigen Seiten findet man beim Hochladen einer Datei eine kleine Leiste, mit der der Status des Uploads angezeigt wird. So auch zum Beispiel auf Vimeo.
So etwas ist auch mit Django relativ einfach zu machen und ich werde in diesem Artikel zeigen, wie es funktioniert.
Warnung: Dieser Artikel ist nicht für Anfänger gedacht und setzt etwas Erfahrung mit Django voraus.
Zuerst erstellen wir ein Django Projekt und editiert die settings.py. Dort fügt man die Datenbankeinstellungen ein, da wir später ein einfaches Model verwenden werden. Ich nenne das Projekt einfach upload.
django-admin.py startproject upload
Als nächstes erstellen wir eine Application. Ich werde die Upload Status Bar an einer einfachen Fotogalerie demonstrieren, also nennen wir diese gallery.
./manage.py startapp gallery
Dort erstellen wir jetzt ein Photo-Model (gallery/models.py):
from django.db import models class Photo(models.Model): photo = models.ImageField('Foto', upload_to='photos/')
Nach dem wir 'gallery' in die INSTALLED_APPS in der settings.py eigetragen haben, können wir die Datenbank synchronisieren:
./manage.py syncdb
Nun erstellen wir einen einfachen View, der alle Bilder anzeigt und auch Uploads zulässt (gallery/views.py):
from django.shortcuts import render_to_response from django.template import RequestContext from django import forms from gallery.models import Photo from django.http import HttpResponseRedirect class PhotoUploadForm(forms.ModelForm): class Meta: model = Photo def gallery(request): if request.method == 'POST': form = PhotoUploadForm(request.POST, request.FILES) if form.is_valid(): form.save() return HttpResponseRedirect(request.path) else: form = PhotoUploadForm() photo_list = Photo.objects.all() return render_to_response('gallery/gallery.html', { 'photo_list': photo_list, 'form': form, }, context_instance=RequestContext(request))
Dazu auch noch das passende Template (gallery/templates/gallery/gallery.html):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3. org/1999/xhtml"> <head> <title>Galerie</title> <style type="text/css"> body { font-family: sans-serif; font-size: 10pt; padding: 25px; margin: 0; } .photo { border: 1px solid #ddd; background-color: #fafafa; padding: 15px; margin: 10px; width: 200px; height: 200px; float: left; } .photo img { max-width: 200px; max-height: 200px; margin: auto; } .upload-progress { position: fixed; left: 0px; bottom: 50px; background-color: #fff; border: 1px solid #ddd; padding: 10px; color: #aaa; text-align: right; } .progress-info span { font-size: 2.25em; font-weight: bold; display: block; } </style> <script type="text/javascript" src="{{ MEDIA_URL }}jquery.js"></script> <script type="text/javascript" src="{{ MEDIA_URL }}upload.js"></script> </head> <body> <h1>Neues Foto hochladen</h1> <form method="post" enctype="multipart/form-data" action="/"> {{ form.as_p }} <p><input type="submit" value="Foto hochladen" /></p> </form> <h1>Fotos ansehen</h1> {% for photo in photo_list %} <div class="photo"> <img src="{{ photo.get_photo_url }}" /> </div> {% endfor %} </body> </html>
Das ganze tragen wir jetzt noch in die URL-Konfiguration ein (urls.py):
(r'^$', 'gallery.views.gallery'),
Jetzt funktioniert der Upload und wir können die Galerie eigentlich schon nutzen. Das sieht dann so aus:
Jetzt wird es etwas komplizierter: Wir müssen einen sogenannten FileUploadHandler “einbinden”. Diesen findet man auf djangosnippets.org. Um diesen nutzen zu können, muss Caching aktiviert sein! Standardmäßig ist das mit dem Wert 'locmem:///' für CACHE_BACKEND der Fall. Das könnte jedenfalls Probleme machen. Am sichersten ist es, wenn man 'file:///foo/bar' oder 'memcached://host:port' nutzt. Dieser Wert darf jedenfalls nicht 'dummy:///' sein!
Jetzt erstellen wir die Datei gallery/uploadhandlers.py und fügen den Code von djangosnippets.org dort ein (bis zu dem Kommentar # A view to report back on upload progress:). Danach müssen wir dir settings.py erneut editieren und diese zwei Zeilen Code hinzufügen:
from django.conf import global_settings FILE_UPLOAD_HANDLERS = ('gallery.uploadhandlers.UploadProgressCachedHandler',) + global_settings.FILE_UPLOAD_HANDLERS
Außerdem müss man in der Datei gallery/uploadhandlers.py die erste Zeile durch die folgende ersetzen, da es im Django Trunk eine entsprechende Änderung gab:
1 | from django.core.files.uploadhandler import FileUploadHandler |
Als nächstes fügen wir den Code nach dem Kommentar in unsere views.py ein. Dann muss nur noch die URL in der urls.py gemappt werden:
(r'^upload_status/$', 'gallery.views.upload_progress'),
Damit sind wir im Python-Code fertig. Der Rest wird Javascript sein. Darum speichern wir zuerst ein Javascript von djangosnippets.org in media/upload.js. Dieses müssen wir jetzt etwas anpassen.
Also müssen wir Zeile 18 so abändern:
18 | var progress_url = '/upload_status/'; // ajax view serving progress info |
Als nächstes müssen wir nur noch jQuery und upload.js einbinden:
<script type="text/javascript" src="{{ MEDIA_URL }}jquery.js"></script> <script type="text/javascript" src="{{ MEDIA_URL }}upload.js"></script>
Jetzt sollte der die Statusanzeige beim Upload funktioniern. Wichtig ist jedoch, dass das das ganze nicht mit dem Development Server funktioniert, da dieser nur eine Anfrage gleichzeitig (in diesem Fall den Upload) verarbeiten kann, wird die AJAX-Anfrage einfach nicht verarbeitet, wodurch die Anzeige durchgehend bei 0% bleibt.
Wichtig ist, dass man zum Testen eine etwas größere Datei nimmt, damit auch Zeit zum Updaten ist. Auch werden die Grafiken einfach durch CSS skaliert, aber hier geht es nur um die Statusanzeige.
Download: Das gesamte Django Project steht auch zum Download bereit. In diesem sind auch noch ein paar kleinere, relativ unwichtige Anpassungen enthalten.
upload.tar.gz (tar.gz, 2,1MB, BSD-Lizenz)
Die Fotos stammen von verschiedenen Flickr-Benutzern:
Chris Seufert, lorenzaccio*, Victor Geere, von Lutz-R. Frank und coda






Super danke, genau auf das habe ich gewartet