2

I'm trying to make it so that when someone tries to upload a file that has already been uploaded before with a model form, the form will prevent it from submitting. Here is the relevant code:

models.py

class File(models.Model):
    file = models.FileField(upload_to='documents/')

forms.py

class FileForm(forms.ModelForm):
    file = forms.FileField()

    class Meta:
        model = File
        fields = ('file',)

views.py

def file_upload(request):
    if request.method == 'POST':
        form = FileForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('list_files')
        else:
            logger.error(form.errors)
    else:
        form = FileForm()

    return render(request, 'files/file_upload.html', {'form': form})

Let's say someone uploaded a file called document_1.xlsx. The way this code is now, if someone tries to upload another file called document_1.xlsx, it will upload it and add some weird suffix to it before the dot. I don't want that. I want the form to not allow anyone upload a file that already exists period, without breaking the code. Apparently adding 'unique=True' to the file field in the model doesn't work. I've seen so many questions that ask how to rename a file if it already exists, but I don't want that. I want to stop it completely if that file name already exists. Thanks.

EDIT:I don't believe this is a duplicate of another question. That question asks how to overwrite a file with the same name. This question is asking how to prevent a file with the same name from uploading.

Jerry Bi
  • 321
  • 6
  • 24
  • Possible duplicate of [How to prevent Django from changing file name when a file with that name already exists?](https://stackoverflow.com/questions/9214904/how-to-prevent-django-from-changing-file-name-when-a-file-with-that-name-already) – Brown Bear Sep 12 '17 at 21:00
  • Docs: https://docs.djangoproject.com/en/1.11/ref/forms/validation/#cleaning-a-specific-field-attribute – allcaps Sep 12 '17 at 21:19

2 Answers2

1

You need to override the default clean method for your form to add the logic of checking if file exists before saving.

Try the below in your FileForm class:

import os
from django.core.exceptions import ValidationError

def clean(self):
    file_path = "your folder/" + self.cleaned_data.get('file')
    if os.path.isfile(file_path):
        raise ValidationError('File already exists') 
    return self.cleaned_data
Hisagr
  • 601
  • 6
  • 13
  • Which module is it supposed to go in? Are you saying that it should go in forms.py within the FileForm class? Should it go before or after the class Meta? – Jerry Bi Sep 12 '17 at 20:53
  • Yes, in your forms.py, after class Meta. – Hisagr Sep 12 '17 at 20:56
  • Apparently adding that gave me this error when I try to upload a file: Can't convert 'InMemoryUploadedFile' object to str implicitly – Jerry Bi Sep 12 '17 at 21:11
  • You just need to str(self.cleaned_data.get('file')) and it will work :) – Hisagr Sep 12 '17 at 21:54
1

You can accomplish this on the clean method of your form. Just check on it whether there is a form with that name. If there is one, Raise a validation error. Something like: (I'm not 100% that this would work. But the solution is down this lines)

def clean_file(self):
    file = self.cleaned_data['file']
    if FileModel.objects.filter(file__name=file.name).exist():
        raise ValidationError('There is already a file with that name on our system')
Julio
  • 170
  • 3