[PYTHON] Djangos ImageField

Vorbereitung

PIL (Pillow) ist erforderlich, um ImageField zu verarbeiten. Wenn Sie sich also nicht in der Python-Ausführungsumgebung befinden, installieren Sie es unten:

pip install pillow
pip3 install pillow # Python 3.x

Ich muss auch MEDIA_ROOT in settings.py definieren, also füge es hinzu:

settings.py


MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

Fügen Sie außerdem Folgendes zu urls.py hinzu:

urls.py


urlpatterns = [
    url(r'^media/(?P<path>.*)$','django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),
]

Was ist ImageField?

In Djangos Modell können verschiedene Felder definiert werden, aber es gibt ** ImageField ** als Feld für die einfache Handhabung von Bilddateien. Hier ist das einfachste Beispiel:

class Image(models.Model):
    image = models.ImageField(upload_to='images/')

Wenn Sie eine Bilddatei speichern, wird sie jetzt mit "MEDIA_ROOT +" images / (Name der ursprünglichen Bilddatei) gespeichert. Wenn der "Name der Originalbilddatei" verdeckt ist, fügt ** Django ein seltsames Suffix hinzu und überschreibt es nicht. ** **.

Ich möchte nicht den ursprünglichen Dateinamen verwenden

Zunächst wollte ich das Bild beim Speichern mit dem Primärschlüssel speichern. Der ursprüngliche Dateiname lautet beispielsweise car.png. Wenn der Primärschlüssel zum Speichern jedoch "id = 123 (pk = 123)" lautet, sollte er in 123.png umbenannt werden.

ImageField kann nicht nur das Zielverzeichnis für das Speichern von Bildern, sondern auch den Dateinamen frei ändern, indem dem Argument "upload_to" eine Funktion zugewiesen wird. Selbst wenn Sie beispielsweise Folgendes tun, wurde die ID beim Aufrufen der Funktion noch nicht abgerufen. Also funktioniert es nicht:

def get_image_path(self, filename):
    prefix = 'images/'
    name = self.id  #In diesem Fall wurde die ID beim Erstellen einer neuen ID noch nicht festgelegt, daher lautet sie "Keine".!!Nicht gut
    extension = os.path.splitext(filename)[-1]
    return prefix + name + extension

Wenn dann "self.id" "None" ist, ist es eine Möglichkeit, "max (id) + 1" aus der DB zu nehmen und zu verwenden, aber es hängt von der DB ab, aber die nächste ID ist nicht unbedingt "max (id)". Es ist nicht streng, weil es nicht zu id) + 1` wird.

Laut StackOverFlow heißt es: "Speichern Sie es vorerst unter einem geeigneten Namen. Wenn die ID nach dem Speichern festgelegt wird, sollten Sie es in den richtigen Dateinamen umbenennen." Das habe ich auch versucht, aber die tatsächliche Datei ist es mit Sicherheit Das ist in Ordnung, aber der Pfad in der Datenbank ist noch alt, daher ist es seltsam, wenn ich ihn mit dem Django-Administrator sehe.

Wenn Sie es beispielsweise später als 123.png speichern und das Bild aktualisieren, können Sie 123.png nicht ** überschreiben, und ** 123 erstellt eine unverständliche Datei mit dem Namen .png. Das liegt daran, dass Django das Überschreiben nicht zulässt. Um dies zu beheben, müssen Sie die alte Datei im Voraus löschen und dann speichern ...

Ich habe es aufgegeben, den Namen der Bilddatei mit dem Primärschlüssel zu speichern, weil es ärgerlich wurde, wenn ich darüber nachdachte.

Sie sollten es wie UUID behalten

Wenn Sie einen normalerweise eindeutigen Dateinamen erstellen möchten, können Sie die UUID verwenden. Daher habe ich Folgendes versucht:

def get_image_path(self, filename):
    """Holen Sie sich einen benutzerdefinierten Bildpfad.

    :param self:Beispiel(models.Model)
    :param filename:Ursprünglicher Dateiname
    :return:Bildpfad mit benutzerdefiniertem Dateinamen
    """
    prefix = 'images/'
    name = str(uuid.uuid4()).replace('-', '')
    extension = os.path.splitext(filename)[-1]
    return prefix + name + extension

Jetzt ist es mit einem Namen wie images / 7f9a9970cc8645a99a2191c114856426.jpg registriert. Wenn ImageField jedoch auf der Verwaltungssite unverändert aktualisiert oder gelöscht wird, wird der DB-Datensatz gelöscht, die Originaldatei bleibt jedoch erhalten. Ich möchte etwas dagegen tun.

Löschen Sie alte Bilddateien beim Aktualisieren oder Löschen

Wie der Titel schon sagt, möchte ich alte Dateien löschen und sie sauberer machen, wenn "save ()" oder "delete ()". Es ist eine gute Idee, den alten Dateipfad vor dem Aktualisieren / Löschen zu speichern und die alte Datei nach der eigentlichen Verarbeitung zu löschen. Hier kommt der Dekorateur ins Spiel.

def delete_previous_file(function):
    """Decorator-Implementierung zum Löschen alter Dateien, die nicht mehr benötigt werden.

    :param function:Hauptfunktion
    :return: wrapper
    """
    def wrapper(*args, **kwargs):
        """Wrapper-Funktion.

        :param args:Willkürliches Argument
        :param kwargs:Beliebiges Schlüsselwortargument
        :return:Ergebnis der Ausführung der Hauptfunktion
        """
        self = args[0]

        #Holen Sie sich den Dateinamen vor dem Speichern
        result = Image.objects.filter(pk=self.pk)
        previous = result[0] if len(result) else None
        super(Image, self).save()

        #Funktionsausführung
        result = function(*args, **kwargs)

        #Löschen Sie alle Dateien vor dem Speichern
        if previous:
            os.remove(MEDIA_ROOT + '/' + previous.image.name)
        return result
    return wrapper

Bereiten Sie eine Funktion für einen solchen Dekorateur vor,

class Image(models.Model):
    @delete_previous_file
    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        super(Image, self).save()

    @delete_previous_file
    def delete(self, using=None, keep_parents=False):
        super(Image, self).delete()

    image = models.ImageField('Bild', upload_to=get_image_path)

Auf diese Weise werden alte Dateien beim Aktualisieren / Löschen gelöscht.

Recommended Posts

Djangos ImageField
Verwenden von Djangos ImageField mit AppEngine / Python
Django order_by notes
Empfohlene Bibliothek von Django
Djangos grundlegendes Memorandum
Über Djangos ProxyModel