Ich habe ein FileField
in einem Modell. Für jede Instanz des Modells möchte ich, dass der Dateiname auf dem Datenträger mit dem Wert eines anderen Feldes (nennen wir es label
) des Modells aktualisiert wird.
Im Moment verwende ich eine benutzerdefinierte Funktion upload_to()
, die den richtigen Dateinamen generiert, wenn eine neue Datei zum ersten Mal hochgeladen wird. Aber wenn ich den Wert von label
ändere, wird der Dateiname beim Speichern des Modells nicht aktualisiert.
In der Funktion save()
des Modells könnte ich (a) den neuen Dateinamen aus label
berechnen (auch prüfen, ob der neue Name nicht mit einer anderen vorhandenen Datei auf der Platte übereinstimmt), (b) die Datei umbenennen auf der Festplatte und (c) setze den neuen Speicherort in FileField
. Aber gibt es keinen einfacheren Weg, das zu tun?
Alle hier veröffentlichten Lösungen und alle Lösungen, die ich im Web gesehen habe, beinhalten die Verwendung von Apps von Drittanbietern oder die Lösung, die Sie bereits haben.
Ich stimme @Phillip zu, es gibt keinen einfacheren Weg, um das zu tun, was Sie wollen, selbst mit der Verwendung von Apps von Drittanbietern würde es etwas Arbeit erfordern, um es an Ihre Zwecke anzupassen.
Wenn Sie viele Modelle haben, die dieses Verhalten benötigen, implementieren Sie einfach ein pre_save signal und schreibe diesen Code nur einmal.
Ich empfehle Ihnen, auch Django-Signale zu lesen, ich bin sicher, Sie werden es finden sehr interessant.
Sehr einfaches Beispiel:
%Vor%Hier ist eine App, die sich darum kümmern kann django-smartfields . Ich habe einen speziellen Prozessor nur für diesen Zweck hinzugefügt, nur weil es wie eine nützliche Funktionalität scheint.
Wie das funktioniert:
upload_to
und FileDependency
wird sich um den Dateinamen kümmern, wenn label
field geändert wird. Beachten Sie, dass die Datei umbenannt wird, indem Sie file_move_safe aber nur im Falle von FileSystemStorage, wie @Phillip erwähnte, dass Sie es nicht mit Cloud-Dateispeicher machen wollen, da diese Backends normalerweise keine Dateiumbenennung unterstützen.
Auch paar Notizen. Sie müssen UploadTo
class nicht verwenden, die reguläre Funktion wird ausreichen. Wenn Sie keep_orphans
nicht angeben, wird die Datei entfernt, sobald die Modellinstanz entfernt wird.
Ok, es kann kein Lambda sein, da Lambdas aus irgendeinem Grund nicht serialisierbar sind, aber hier ist die einfache Antwort.
%Vor%Dann finden Sie sagen pk = 1 mit:
slug = 'new-thing' wäre //meinbeispiel.com/MEDIA_ROOT/1/new-thing/mything.png
%Vor%Dies setzt voraus, dass MEDIA_ROOT eingestellt ist, da Uploads auf die Medien- und Medien-URL gehen. Dienen Sie, wie Sie statische Dateien getan haben, wenn Sie in Produktion sind, nennen Sie es nach MEDIA_URL.
upload_to übergibt sowohl die Objektinstanz als auch den Dateinamen an eine Funktion, von dort aus können Sie sie manipulieren.
Um den tatsächlichen Dateinamen zu ändern, müssen Sie in der save () -Methode etwas mehr arbeiten.
%Vor%Wenn die Dateierweiterung wichtig ist, was sie sehr gut sein kann, fügen Sie sie entweder zur Beschriftung hinzu, wenn Sie eine Beschriftung erstellen, oder wir nehmen die alte Dateierweiterung als Teil der Zeichenfolge:
%Vor%Ich würde vorschlagen, eine Umbenennungsfunktion als Teil Ihrer app_label.utils
zu schreibenUm zu überprüfen, ob die Datei existiert, ist einfach
%Vor%Ich denke, Ihr Ansatz mit der Methode save () ist der richtige und "einfache", außer dass ich das pre_save-Signal verwenden würde, anstatt die Speichermethode zu überschreiben (was oft eine schlechte Idee ist).
Wenn dies ein Verhalten ist, das Sie bei anderen Modellen wiederholen möchten, können Sie mit einer Methode, die mit dem pre_save-Signal verbunden ist, die Methode einfach erneut verwenden.
Weitere Informationen zu pre_save: Ссылка