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.
Stefan Feb. 11, 2008
Hey, vielen Dank für den nützlichen Tipp, den werde ich definitiv noch gebrauchen können!
Nicole Feb. 19, 2008
Danke für die super Infos. Werde jetzt öfters vorbeischauen! also bitte mehr davon!
Helmut Feb. 21, 2008
Funktioniert prima mit thunmbs erzeugen. Nur leider zeigt es die thumbs bei mir nicht an
luis Aug. 19, 2008
update für django-trunk: Bei djangosnippets