Django FileField "upload_to" method is not called when calling save () with commit = False
Context: I want to take a user uploaded file, attach it to the model, change some properties, and then save the object to the database.
Here's some code:
def file_upload_path(instance, filename): path = os.path.join('uploaded_files', str(uuid4())) return path class UploadedFile(models.Model): file_object = models.FileField(null=False, blank=False, upload_to=file_upload_path) def __unicode__(self): return self.file_object.name
class UploadFileForm(forms.ModelForm): class Meta: model = UploadedFile fields = ['file_object']
def home(request): ... if form.is_valid(): new_file = form.save(commit=True) print new_file ...
This code prints exactly what I want, it is the file path after upload_to is called and the file has been saved to the specified location (eg "uploaded_files / b992e44e-6403-4c37-82b4-b3c403d07f79").
Now, with this views.py, things change:
def home(request): ... if form.is_valid(): new_file = form.save(commit=False) print new_file # new_file_object = FileObject(os.path.abspath(new_file.file_object.url)) # new_file.mime_type = new_file_object.get_mime_type() ...
Instead of a path, I get the original filename (eg "jnes.exe"), so I cannot process the file to, for example, get its mime type and then update the model and save its databases.
Any ideas what I am doing wrong? Thank.
How I got around this:
I am making the necessary changes to the model on a file that is still in memory / temporarily on disk, as Django does not allow you to directly find the location of the FileField until you actually save an instance of the new model.
def save(self, commit=True, *args, **kwargs): new_model = super(UploadFileForm, self).save(commit=False) file_object = self.cleaned_data['file_object'] file_info = FileObject(file_object) new_model.mime_type = file_info.get_mime_type() new_model.sha256 = file_info.get_sha256() new_model.md5 = file_info.get_md5() if commit: new_model.save() return new_model
I am getting the hashes and mime type in the FileObject constructor by reading data from a temporary Django UploadedFile object. (thanks to Daniel)
source to share
docs specify the following
The file is saved as part of saving the model to the database, so the actual file name used on disk cannot be relied upon until the model is saved.
So, you are not wrong. It will not be there until it is perfect.
If you want to process the file in any way before saving it. You will want to access it when it is a temporary file. This answer can help you with this alternative way of accessing the file to get mimetype etc.
source to share