django - tutorial - ImageField überschreibt die Bilddatei mit demselben Namen




django tutorial (6)

ähm ... das hört sich vielleicht unkonventionell an, aber meine Lösung ist derzeit, die existierende Datei innerhalb des Callbacks zu überprüfen und zu entfernen, den ich bereits verwende, um den Namen der hochgeladenen Datei anzugeben. In models.py:

import os
from django.conf import settings

def avatar_file_name(instance, filename):
    imgname = 'whatever.xyz'
    fullname = os.path.join(settings.MEDIA_ROOT, imgname)
    if os.path.exists(fullname):
        os.remove(fullname)
    return imgname
class UserProfile(models.Model):
    avatar = models.ImageField(upload_to=avatar_file_name,
                                default=IMGNOPIC, verbose_name='avatar')

https://code.i-harness.com

Ich habe ein Model UserProfile mit field avatar = models.ImageField(upload_to=upload_avatar)

upload_avatar Funktionsnamen Image-Datei entsprechend user.id (12.png zum Beispiel).

Aber wenn der Benutzer den Avatar aktualisiert, stimmt der neue Avatarname mit dem alten Avatarnamen überein, und Django fügt dem Dateinamen einen Suffix hinzu (zum Beispiel 12-1.png).

Es gibt Möglichkeiten, Dateien zu überschreiben anstatt neue Dateien zu erstellen ?


Für Django 1.10 fand ich, dass ich die oberste Antwort modifizieren musste, um das Argument max_length in die Funktion einzufügen:

from django.core.files.storage import FileSystemStorage
import os

class OverwriteStorage(FileSystemStorage):
def get_available_name(self, name, max_length=None):
    if self.exists(name):
        os.remove(os.path.join(settings.MEDIA_ROOT, name))
    return name

Ja, das ist auch für mich gekommen. Hier ist, was ich getan habe.

Modell:

from app.storage import OverwriteStorage

class Thing(models.Model):
    image = models.ImageField(max_length=SOME_CONST, storage=OverwriteStorage(), upload_to=image_path)

Auch in models.py definiert:

def image_path(instance, filename):
    return os.path.join('some_dir', str(instance.some_identifier), 'filename.ext')

In einer separaten Datei storage.py:

from django.core.files.storage import FileSystemStorage
from django.conf import settings
import os

class OverwriteStorage(FileSystemStorage):

    def get_available_name(self, name):
        """Returns a filename that's free on the target storage system, and
        available for new content to be written to.

        Found at http://djangosnippets.org/snippets/976/

        This file storage solves overwrite on upload problem. Another
        proposed solution was to override the save method on the model
        like so (from https://code.djangoproject.com/ticket/11663):

        def save(self, *args, **kwargs):
            try:
                this = MyModelName.objects.get(id=self.id)
                if this.MyImageFieldName != self.MyImageFieldName:
                    this.MyImageFieldName.delete()
            except: pass
            super(MyModelName, self).save(*args, **kwargs)
        """
        # If the filename already exists, remove it as if it was a true file system
        if self.exists(name):
            os.remove(os.path.join(settings.MEDIA_ROOT, name))
        return name

Natürlich sind das hier Beispielwerte, aber insgesamt funktioniert das gut für mich und das sollte ziemlich einfach geändert werden können, wenn es nötig ist.


Sie können die Speicherklasse auf diese Weise noch besser schreiben:

class OverwriteStorage(FileSystemStorage):

    def get_available_name(self, name, max_length=None):
        self.delete(name)
        return name

Im Grunde überschreibt dies die Funktion get_available_name , um die Datei zu löschen, wenn sie bereits existiert, und den Namen der bereits gespeicherten Datei zurückzugeben


Verändern Sie einfach Ihr Modellbildfeld, löschen Sie es und speichern Sie es erneut.

model.image.delete()
model.image.save()

class OverwriteStorage(get_storage_class()):

    def _save(self, name, content):
        self.delete(name)
        return super(OverwriteStorage, self)._save(name, content)

    def get_available_name(self, name):
        return name




django-models