So, I'm working on implementing the answer to my previous question.
Here's my model:
class Talk(models.Model):
title = models.CharField(max_length=200)
mp3 = models.FileField(upload_to = u'talks/', max_length=200)
Here's my form:
class TalkForm(forms.ModelForm):
def clean(self):
super(TalkForm, self).clean()
cleaned_data = self.cleaned_data
if u'mp3' in self.files:
from mutagen.mp3 import MP3
if hasattr(self.files['mp3'], 'temporary_file_path'):
audio = MP3(self.files['mp3'].temporary_file_path())
else:
# What goes here?
audio = None # setting to None for now
...
return cleaned_data
class Meta:
model = Talk
Mutagen needs file-like objects or filenames on disk (I think) - the first case (where the uploaded file is larger than the size of file handled in memory) works fine, but I don't know how to handle InMemoryUploadedFile
that I get otherwise. I've tried:
# TypeError (coercing to Unicode: need string or buffer, InMemoryUploadedFile found)
audio = MP3(self.files['mp3'])
# TypeError (coercing to Unicode: need string or buffer, cStringIO.StringO found)
audio = MP3(self.files['mp3'].file)
# Hangs seemingly indefinitely on my test file (~800KB)
audio = MP3(self.files['mp3'].file.read())
Is there something wrong with mutagen, or am I doing it wrong?
Modifying the FILE_UPLOAD_HANDLERS
setting on the fly in my ModelAdmin
class like this:
def add_view(self, request, form_url='', extra_context=None):
request.upload_handlers = [TemporaryFileUploadHandler()]
return super(TalkAdmin, self).add_view(request, form_url, extra_context)
Gets me the following error 500 when I hit submit:
You cannot set the upload handlers after the upload has been processed.
even though I'm doing it as early as I possibly can!
Also, I'm not sure I've got a save
method on the object I'm getting back (I've looked in dir(self.files['mp3'].file)
and dir(self.files['mp3'])
).
cleaned_data is where all validated fields are stored.
The clean() method on a Field subclass is responsible for running to_python() , validate() , and run_validators() in the correct order and propagating their errors. If, at any time, any of the methods raise ValidationError , the validation stops and that error is raised.
Use the has_changed() method on your Form when you need to check if the form data has been changed from the initial data. has_changed() will be True if the data from request.
If yes try to disable this behavior, set the novalidate attribute on the form tag As <form action="{% url 'new_page' %}", method="POST" novalidate> in your html file.
You could try to change your FILE_UPLOAD_HANDLERS in such a way so Django always uses temporay file handler:
FILE_UPLOAD_HANDLERS
default:
("django.core.files.uploadhandler.MemoryFileUploadHandler",
"django.core.files.uploadhandler.TemporaryFileUploadHandler",)
So you could leave only TemporaryFileUploadHandler
by overriding the setting in your settings.py.
Edit:
Much simpler, should have thought of it at the first place :(:
from your.models import Talk
mp3 = self.files['mp3']
f = Talk.mp3.save('somename.mp3', mp3)
MP3(f.mp3.path)
>>> {'TRCK': TRCK(encoding=0, text=[u'5'])}
You can save InMemoryUploadedFile
to the disk this way and then use the path to that file to work with mutagen
.
Edit:
Same thing without a models instance.
import os
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from django.conf import settings
from mutagen.mp3 import MP3
mp3 = request.FILES['mp3'] # or self.files['mp3'] in your form
path = default_storage.save('tmp/somename.mp3', ContentFile(mp3.read()))
MP3(os.path.join(settings.MEDIA_ROOT, path))
Note that it's saving the file in MEDIA_ROOT, when i try to save it anywhere else i get SuspiciousOperation since there are limits to where you can write... You should delete this file after examining it i guess, the real thing will be on your model...
path = default_storage.delete('tmp/somename.mp3')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With