84π
Yeah, this has come up for me, too. Hereβs what Iβve done.
Model:
from app.storage import OverwriteStorage
class Thing(models.Model):
image = models.ImageField(max_length=SOME_CONST, storage=OverwriteStorage(), upload_to=image_path)
Also defined in models.py:
def image_path(instance, filename):
return os.path.join('some_dir', str(instance.some_identifier), 'filename.ext')
In a separate file, 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
Obviously, these are sample values here, but overall this works well for me and this should be pretty straightforward to modify as necessary.
29π
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, max_length=None):
return name
- [Django]-How to format dateTime in django template?
- [Django]-How to import csv data into django models
- [Django]-A field with precision 10, scale 2 must round to an absolute value less than 10^8
26π
You can write storage class even better this way:
class OverwriteStorage(FileSystemStorage):
def get_available_name(self, name, max_length=None):
self.delete(name)
return name
Basically this will overwrite the function get_available_name
to delete the file if already exists and return the name of the file already storaged
- [Django]-RuntimeError: Model class django.contrib.sites.models.Site doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS
- [Django]-Django switching, for a block of code, switch the language so translations are done in one language
- [Django]-What is actually assertEquals in Python?
13π
Just refference your model image field, delete it and save again.
model.image.delete()
model.image.save()
- [Django]-Django: OperationalError No Such Table
- [Django]-DRY way to add created/modified by and time
- [Django]-Getting 'DatabaseOperations' object has no attribute 'geo_db_type' error when doing a syncdb
12π
ahem⦠it may sound unorthodox, but my solution, at present, is to check&remove the existing file within the callback I already use for providing the name of the uploaded file. 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')
- [Django]-Error: "dictionary update sequence element #0 has length 1; 2 is required" on Django 1.4
- [Django]-How can I chain Django's "in" and "iexact" queryset field lookups?
- [Django]-Django class-based view: How do I pass additional parameters to the as_view method?
8π
For Django 1.10 I found I had to modify the top answer to include the max_length argument in the Function:
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
- [Django]-Django: best practice way to get model from an instance of that model
- [Django]-Django Rest Framework Token Authentication
- [Django]-Adding a user to a group in django
6π
You can try to define your own Filesystemstorage and override the default get_availbale_name method.
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
For your image you could define a fs like this:
fs = MyFileSystemStorage(base_url='/your/url/',
location='/var/www/vhosts/domain/file/path/')
avatar = models.ImageField(upload_to=upload_avatar, storage=fs)
Hope this helps.
- [Django]-Django filter many-to-many with contains
- [Django]-ImproperlyConfiguredError about app_name when using namespace in include()
- [Django]-CSS styling in Django forms
0π
I tried the solutions mentioned here. But it seem not to work at django 1.10. It would raise the following error somewhere at the adminβs template:
url() missing 1 required positional argument: 'name'
So I came up with my own solution, which consists on creating a pre_save signal that tries to get the instance from the database before itβs saved and remove itβs file path:
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)
- [Django]-Django templates: verbose version of a choice
- [Django]-Cross domain at axios
- [Django]-Django staticfiles not found on Heroku (with whitenoise)
0π
in Django 4.2 You can try to define your own Filesystemstorage and override the default exists method.
class OverwriteStorage(FileSystemStorage):
def exists(self, name):
exists = os.path.lexists(self.path(name))
if exists:
os.remove(os.path.join(settings.MEDIA_ROOT, name))
return exists
and define your model with a new filesystem class
class IMGUpload(TimeStampMixin):
file = models.FileField(blank=False, null=False,
storage=OverwriteStorage(),
upload_to=get_uploaded_file_path,
validators=[validate_file_extension])
- [Django]-Django 1.7 β "No migrations to apply" when run migrate after makemigrations
- [Django]-Location of Django logs and errors
- [Django]-Profiling Django