Vorschaubilder in Djangos Administration
Geschrieben 6 Monate, 1 Woche zuvor
Vielleicht hast du ja eine Bildergalerie auf deiner Seite und ärgerst dich im Admin, das du kaum Übersicht über die Bilder hast. Dieses Tutorial zeigt, wie man kleine Vorschaubilder (Thumbnails) in Djangos Administrationsoberfläche anzeigt.
Das Minimal-Model
Für dieses Beispiel erstelle ich ein Model mit nur 4 Feldern; dem Bildtitel, einem Beschreibungstext, dem Veröffentlichungsdatum und dem Bild-Feld, in diesem Fall ein models.ImageField, dass den Upload und Pfad des Bildes verwaltet.
# -*- coding: utf-8 -*- from django.db import models class GalleryImage(models.Model): title = models.CharField('Titel', max_length=250) description = models.TextField('Beschreibung', blank=True) pub_date = models.DateTimeField('Hinzugefügt', auto_now_add=True) image = models.ImageField('Bild', upload_to='bilder/') class Admin: list_display = ( 'title', 'image', 'description', 'pub_date', ) def __unicode__(self): return str(self.id)
Dein Bildergalerie-Model wird wahrscheinlich ähnlich aussehen. Mit ein paar Daten und Bildern schaut das ganze bei mir nun so aus:
Nichts bedeutsames. Unser Ziel ist es, auf dieser Seite das Bild als kleines Vorschaubild anzuzeigen. Dir ist sicher schon das Attribut list_display aufgefallen. In ihr kannst du festlegen, welche (Model)Spalten in der Übersicht angezeigt werden sollen. Jetzt sind es die Spalten Titel, Image (der Bild-Dateiname), die Beschreibung und das Veröffentlichungsdatum.
Diese Liste ist aber nicht auf die Model-Felder beschränkt, man kann auch eigene Model-Methoden definieren.
Um das Bild auf der Administration anzuzeigen, genügt eine simple Methode, die den Bildnamen (Beispiel: /bilder/test.jpg) mit deiner Media-URL (siehe settings.py, Beispiel: /media/) verknüpft und zurück gibt. Ein Beispiel währe: /media/bilder/test.jpg/.
Wer unter Windows arbeitet weiß, dass Verzeichnisse mit einem "\" getrennt, in diesem Fall ändern wir daher zusätzlich noch alle "\\" in einen Schrägstrich "/".
Die zusätzliche Meta-Information short_description für diese Methode beschreibt den Titel der Spalte und allow_tags verrät Django, dass in dieser Spalte HTML erlaubt ist.
import urlparse from django.conf import settings from django.db import models class GalleryImage(models.Model): # ... class Admin: list_display = ( 'title', 'image', 'preview_image_url', # Die Model-Methode preview_image_url() 'description', 'pub_date', ) def preview_image_url(self): image_path = self.image # Die URL des Bildes, Bspw. /gallery/image.jpg image_path = image_path.replace('\\','/') # Windows-Fix image_path = urlparse.urljoin(settings.MEDIA_URL, image_path) return '<a href="'+ str(self.id) +'/"><img src="'+ str(image_path) +'"/></a>' preview_image_url.short_description = 'Thumbnail' preview_image_url.allow_tags = True
Die paar Zeilen reichen und schon haben wir zu jedem Eintrag ein Vorschaubild:
Viel zu groß!
Schon ganz nett, oder? Das Problem ist aber auf den ersten Blick zu sehen: Das erste Bild ist viel zu groß. Wer richtig große Bilder – in der Größe von 1600x1200px oder mehr – im Model speichert, wird außer einem Bild nicht mehr sehen. Ein Thumbnail-Filter muss her!
Für dieses Beispiel benutze ich den Thumbnail-Filter von michelts aus den Djangosnippets. Du brauchst die Python Imaging Library (PIL) die du z.B. unter Debian/Ubtuntu ganz einfach über den Befehl:
apt-get install python-imaging
installieren kannst. Der Filter selbst funktioniert sehr einfach:
- Man übergibt ihm die Bild-URL aus dem ImageField,
- er erstellt ein Thumbnail variabler Größe daraus,
- speichert das Bild in selben Verzeichnis mit dem Dateinamen dateiname_BREITExHÖHE.jpg,
- und gibt die neue Thumnail-URL zurück.
Schau auch in die Kommentare, dort ist eine Erweiterung beschrieben, wie sich das Thumbnail automatisch aktualisiert, wenn sich das Original-Bild ändert. Dazu verrate ich euch noch gleich ein Fix, damit die Thumbnails mittels AntiAliasing verkleinert werden und somit unschöne Kanten verschwinden.
Ändere den Thumbnail Code ab:
image.thumbnail([x, y]) # generate a 200x200 thumbnail # Wird zu image.thumbnail([x, y], Image.ANTIALIAS) # generate a 200x200 thumbnail
Unsere verbesserte Thumbnail-Vorschau-Funktion im Model schaut nun so aus:
# Die Thumbnail-Funktion liegt in einer Datei "utils.py" im # selben Verzeichnis wie die Model-Definition from my_project.gallery.utils import thumbnail class GalleryImage(models.Model): # ... def preview_image_url(self): image_path = thumbnail(self.image, '60x60') # Ein 60x60 Pixel großes Thumbnail soll erstellt werden # Rückgabe Beispiel: http://static.example.com/gallery/image_60x60.jpg # MEDIA_URL:^^^^^^^^^^^^^^^^^^^^^^^^^ image_path = image_path.replace('\\','/') # Windows-Fix return '<a href="'+ str(self.id) +'/"><img src="'+ str(image_path) +'"/></a>'
Und die Ausgabe? Der "viel zu große Schwammkopf" ist nun auf Normalgröße geschrumpft.
Ganz ohne Wasserverlust.
Nochmal zur Übersicht das ganze Model:
# -*- coding: utf-8 -*- import urlparse from django.db import models from my_project.gallery.utils import thumbnail class GalleryImage(models.Model): title = models.CharField('Titel', max_length=250) description = models.TextField('Beschreibung', blank=True) pub_date = models.DateTimeField('Hinzugefügt', auto_now_add=True) image = models.ImageField('Bild', upload_to='bilder/') class Admin: list_display = ( 'title', 'image', 'preview_image_url', 'description', 'pub_date', ) def preview_image_url(self): image_path = thumbnail(self.image, '60x60') image_path = image_path.replace('\\','/') # Windows-Fix return '<a href="'+ str(self.id) +'/"><img src="'+ str(image_path) +'"/></a>' preview_image_url.short_description = 'Thumbnail' preview_image_url.allow_tags = True def __unicode__(self): return str(self.id)
Dieses Beispiel wird fortgesetzt. Im nächsten Tutorial zeige ich euch, wie man die Thumbnail-Funktion nicht nur auf Bilder aus einem ImageField beschränkt.
Update
Im Beispiel hat sich ein Fehler eingeschlichen. Um die URL des Medien-Stammordners MEDIA_URL und die URL des Bildes image_path zu verknüpfen, war die os.path.join Funktion schlichtweg falsch. (Auch wenn sie ein plausibles Ergebniss lieferte.) Die korrekte Funktion zum verketten von URLs ist urlparse.urljoin.
Unter Linux und mit einem lokalen Webserver fiel der Fehler nicht auf. Wer unter Windows
entwickelt, wird u.U. kein Bild zu sehen bekommen.
Der selbe Fehler ist auch
im Snippet zu finden, dort sollte die
Zeile #16:
miniature_url = os.path.join(settings.MEDIA_URL, miniature
abgeändert werden in:
from urlparse import urljoin miniature_url = urljoin(settings.MEDIA_URL, miniature)
In den obigen Beispielen ist der Fehler berichtigt.








12:39 Uhr
Hey, vielen Dank für den nützlichen Tipp, den werde ich definitiv noch gebrauchen können!
10:46 Uhr
Danke für die super Infos. Werde jetzt öfters vorbeischauen! also bitte mehr davon!
12:14 Uhr
Funktioniert prima mit thunmbs erzeugen. Nur leider zeigt es die thumbs bei mir nicht an
12:56 Uhr
update für django-trunk: Bei djangosnippets