update type example decimalfield django django-models

django - type - ImageField sobrescribe el archivo de imagen con el mismo nombre



type models django (8)

Intenté las soluciones mencionadas aquí. Pero parece que no funciona en django 1.10. Se generaría el siguiente error en alguna parte de la plantilla del administrador:

url() missing 1 required positional argument: ''name''

Así que se me ocurrió mi propia solución, que consiste en crear una señal pre_save que intente obtener la instancia de la base de datos antes de que se guarde y eliminarla.

from django.db.models.signals import pre_save @receiver(pre_save, sender=Attachment) def attachment_file_update(sender, **kwargs): attachment = kwargs[''instance''] # As it was not yet saved, we get the instance from DB with # the old file name to delete it. Which won''t happen if it''s a new instance if attachment.id: attachment = Attachment.objects.get(pk=attachment.id) storage, path = attachment.its_file.storage, attachment.its_file.path storage.delete(path)

Tengo el modelo UserProfile con el campo avatar = models.ImageField(upload_to=upload_avatar)

archivo de imagen de nombres de función user.id según user.id (12.png por ejemplo).

Pero cuando el usuario actualiza el avatar, el nuevo nombre del avatar coincide con el antiguo nombre del avatar y Django agrega el sufijo al nombre del archivo (12-1.png, por ejemplo).

¿Hay forma de sobrescribir el archivo en lugar de crear un nuevo archivo ?


Para Django 1.10 encontré que tenía que modificar la respuesta superior para incluir el argumento max_length en la función:

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


Puede escribir la clase de almacenamiento aún mejor de esta manera:

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

Básicamente, esto sobrescribirá la función get_available_name para eliminar el archivo si ya existe y devolver el nombre del archivo ya almacenado.


Puede tratar de definir su propio sistema de archivos y reemplazar el método predeterminado get_availbale_name.

from django.core.files.storage import FileSystemStorage import os class MyFileSystemStorage(FileSystemStorage): def get_available_name(self, name): if os.path.exists(self.path(name)): os.remove(self.path(name)) return name

Para su imagen, podría definir un fs como este:

fs = MyFileSystemStorage(base_url=''/your/url/'', location=''/var/www/vhosts/domain/file/path/'') avatar = models.ImageField(upload_to=upload_avatar, storage=fs)

Espero que esto ayude.


Sí, esto también me ha venido a mí. Esto es lo que hice.

Modelo:

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

También se define en models.py:

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

En un archivo separado, 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

Obviamente, estos son valores de muestra aquí, pero en general, esto funciona bien para mí y esto debería ser bastante sencillo de modificar según sea necesario.


Simplemente refiera su campo de imagen modelo, elimínelo y vuelva a guardarlo.

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


ejem ... puede sonar poco ortodoxo, pero mi solución, en este momento, es verificar y eliminar el archivo existente dentro de la devolución de llamada que ya uso para proporcionar el nombre del archivo cargado. En 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'')


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