Search code examples
djangodjango-uploads

How does Django rename uploaded files?


If upload a file image.png from a web browser, a new file named image.png will appear in the upload directory on the server.

If I then upload another file named image.png (same name), a new file named image_aj642zm.png will appear in the upload directory on the server.

Then, if I upload another file named image.png (again the same name), a new file named image_z6z2BaQ.png will appear in the upload directory on the server.

What method does Django use to rename the uploaded file if a file with that name already exists in the upload directory? (i.e. where does the extra _aj642zm and _z6z2BaQ come from?)

The usual set-up:

In models.py:

from django.db import models

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

In forms.py:

from django import forms
from .models import Image

class ImageForm(forms.ModelForm):
    class Meta:
        model = Image
        fields = ['image']

In views.py:

from django.shortcuts import render, redirect
from .forms import ImageForm

def upload_image(request):
    if request.method == 'POST':
        form = ImageForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('index')
        else:
            form = ImageForm()

    return render(request, 'upload_file.html', {'form': form})

Solution

  • Django default Storage class method called get_available_name

        # If the filename already exists, add an underscore and a random 7
        # character alphanumeric string (before the file extension, if one
        # exists) to the filename until the generated filename doesn't exist.
        # Truncate original name if required, so the new filename does not
        # exceed the max_length.
    

    Django by default saves object by its name but if object with that name already exists adds up underscore and 7 random chars as quoted in code comment

    Also as addition to this Django Storage class method get_valid_name parses up file name before and replaces all spaces with underscores and removes all chars that are not unicode, alpha, dash, underscore or dot

    re.sub(r'(?u)[^-\w.]', '', s)