2

I would like to keep the original file name of an UploadedFile in Django that has its location stored in a FileField. Right now I am observing that if two files have the same name, the first file uploaded keeps its original name but the second time a file with that name is uploaded, it has a random string appended to make the file name unique. One solution is to add an additional field to the model: Django: How to save original filename in FileField? or Saving Original File Name in Django with FileField but these solutions seem suboptimal as they require changing the Model fields.

An alternative would be to prepend a random directory path to the front of the file make sure that in a given directory the file name is unique and allowing the basename to remain unchanged. One way to do this would be to pass in a callable upload_to that does just that. Another option would be to subclass FileField and override get_filename to not strip the input filename to the basename allowing the caller to pass in a filename with a prepended path. The latter option is not ideal if I want to use an ImageField as I would have to subclass that as well.

Community
  • 1
  • 1
Alex Rothberg
  • 10,243
  • 13
  • 60
  • 120

3 Answers3

2

In looking at the code that actually generates the unique filename by appending the random string, it looks like the best solution to this problem might be to subclass the Storage class in-use and override get_available_name method to create unique filenames by prepending a directory rather than post-pending the string to the base name.

Alex Rothberg
  • 10,243
  • 13
  • 60
  • 120
0

Sorry for the quick answere, here is another approach to your question : The idea here is to create an unique folder for each uploaded file.

# in your settings.py file
MY_FILE_PATH = 'stored_files/'

The path were your files will be stored : /public/media/stored_files

# somewhere in your project create an utils.py file
import random
try:
    from hashlib import sha1 as sha_constructor
except ImportError:
    from django.utils.hashcompat import sha_constructor


def generate_sha1(string, salt=None):
    """
    Generates a sha1 hash for supplied string.

    :param string:
        The string that needs to be encrypted.

    :param salt:
        Optionally define your own salt. If none is supplied, will use a random
        string of 5 characters.

    :return: Tuple containing the salt and hash.

    """
    if not isinstance(string, (str, unicode)):
         string = str(string)
    if isinstance(string, unicode):
        string = string.encode("utf-8")
    if not salt:
        salt = sha_constructor(str(random.random())).hexdigest()[:5]
    hash = sha_constructor(salt+string).hexdigest()

    return (salt, hash)

In your models.py

from django.conf import settings
from utils.py import generate_sha1

def upload_to_unqiue_folder(instance, filename):
    """
    Uploads a file to an unique generated Path to keep the original filename
    """

    salt, hash = generate_sha1('{}{}'.format(filename, get_datetime_now().now))

    return '%(path)s%(hash_path)s%(filename)s' % {'path': settings.MY_FILE_PATH,
                                               'hash_path': hash[:10],
                                               'filename': filename}



#And then add in your model fileField the uplaod_to function
class MyModel(models.Model):
    file = models.FileField(upload_to=upload_to_unique_folder)

The file will be uploaded to this location :

public/media/stored_file_path/unique_hash_folder/my_file.extention

Note : I got the code from Django userena sources, and adapted it to my needs

Note2 : For more informations take a look at this greate post on Django File upload : File upload example

Have a good day.

Edit : Trying to provide a working solution :)

Community
  • 1
  • 1
-2

To my understanding, during the form submission/file upload process, you can add form validation functions.

During the validation and cleaning process, you could check that the database does not already have a duplicate name (ie. query to see if that file name exists).

If it is duplicate, you could just rename it xyz_1, xyz_2, etc

conrad
  • 1,783
  • 14
  • 28
  • see [this](https://docs.djangoproject.com/en/dev/ref/forms/validation/#cleaning-a-specific-field-attribute) for reference – conrad Nov 04 '14 at 10:07
  • The issue is this is appending a string to the name. I would have to strip it off on serving it back up. Also how do I know if the first file already ended with an underscore and then a number? I would have to escape too. – Alex Rothberg Nov 04 '14 at 13:48
  • you could for example prepend or append a time stamp to the file name (eg: xyz_20140101121259). a time stamp that goes down to the milliseconds, and u know exactly the length of this time stamp, so it will be easy to strip it out when you serve it back up – conrad Nov 05 '14 at 03:09
  • This is good almost all of the time, but again there is no guarantee that two files won't be uploaded in the same millisecond. – Alex Rothberg Nov 05 '14 at 21:43
  • if you are so worried about that then do 20140101121259001, 20140101121259002 etc. – conrad Nov 06 '14 at 02:13