Überschreiben hochgeladener Dateien
Wird eine Datei für ein FileField oder ImageField hochgeladen und exisitiert bereits, überschreibt Django diese Datei nicht sondern hängt einen Tiefstrich an die Datei. Die ältere Datei bleibt ohne Verweis im Dateisystem bestehen.
Überschreibst du also eine Datei rechnung.pdf drei mal, entsteht eine lustige Kaskade im Dateisystem.
- rechnung.pdf
- rechnung_.pdf
- rechnung__.pdf
- rechnung___.pdf (Der Pfad zu dieser Datei wird im FileField gespeichert)
Es ist nicht immer im Interesse, diese alten Dateien zu behalten. Sei es aus Platzmangel, Datenschutzgründen oder weil man einfach nur Ordnung auf seinem System halten will.
Derzeit gibt es keinen direkten Weg, das überschreiben zu erzwingen. Es gibt schon seit längerer Zeit ein Ticket im Django-Repository aber es schaut nicht so aus, als ob es in Django 1.1 eingespielt wird.
Automatisches Übeschreiben mit einem Custom-Storage ###
Hochgeladene Dateien werden von einem eigenen Modul, dem FileSystemStorage verarbeitet. Es öffnet und speichert die Dateien und prüft, ob der Dateiname schon exisitiert und hängt ggf. einen Tiefstrich an die Datei. Das passiert in der Methode get_available_name. Genau diese ist der Ansatzpunkt um das Überschreiben zu erzwingen.
Hier wird ein eigenes Storage erstellt aber vor dem Speichern der Datei, wird (wenn sie existiert) die alte Datei gelöscht:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from django.db import models from django.core.files.storage import FileSystemStorage class OverwriteFileSystemStorage(FileSystemStorage): def get_available_name(self, name): if self.exists(name): self.delete(name) return name class Invoice(models.Model): title = models.CharField(max_length=120) invoice = models.FileField(upload_to=upload_invoice, storage=OverwriteFileSystemStorage()) def __unicode__(self): return self.title |
Das Custom-Storage wird dem FileField oder dem ImageField als Attribut storage übergeben. Soll dieses Schema für alle Uploads gelten, ändere in der settings.py den Wert DEFAULT_FILE_STORAGE Standardmässig wird das oben genannte FileSystemStorage verwendet.
1 2 3 4 5 | # Original DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage' # Immer alle Dateien überschreiben DEFAULT_FILE_STORAGE = 'path.to.OverwriteFileSystemStorage' |
Den originalen Dateinamen zusätzlich speichern
Dass Dateien nicht grundsätzlich überschrieben werden ist ja grundsätzlich keine schlechte Idee. Schließlich hat man immer ein automatisches Backup aller Änderungen. Lassen wir das Schema so wie es ist aber speichern wir den originalen Dateinamen zusätzlich in einem eigenen Feld. So können wir dem User später den orignalen Dateinamen anzeigen, im Dateisystem bleiben aber alle überschriebenen Dateien erhalten.
Ein upload-Callable ist ein schneller und sicherer Weg, dies zu erreichen. Mehr dazu hatte ich schon in Ordnung im Medienordner geschrieben.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | from django.db import models class Invoice(models.Model): def upload_invoice(instance, filename): instance.invoice_orig_filename = filename return filename title = models.CharField(max_length=120) invoice = models.FileField(upload_to=upload_invoice, storage=OverwriteFileSystemStorage()) invoice_orig_filename = models.CharField(max_length=100, blank=True) def __unicode__(self): return self.title |
Dateien löschen

Der Vollständigkeit halber: Von Haus aus ist es im Admin noch nicht möglich, hochgeladene Dateien wieder zu löschen. Stephan Jäkel hat ein Admin-Widget konstruiert, dass Dateien auf Klick wieder löscht.
Geschrieben am: 09. April 2009 um 12:44 Uhr, Abgelegt in Django & Python
Kommentare zu diesem Artikel (2):
-
flosch schrieb am 09. April 2009:
Dein zweiter Beitrag innerhalb von 24 Stunden - du willst wohl Mitarbeiter des Monats werden
Wie immer, toller und hilfreicher Beitrag, danke! -
nicole schrieb am 02. Mai 2009:
Danke,
die Striche waren mir scho immer ein Dorn im Auge...
Bye Nicole (sms-puls.de)
Kommentar schreiben