Чтение данных файла во время метода очистки формы

Итак, я работаю над реализацией ответа на мой предыдущий вопрос .

Вот моя модель:

class Talk(models.Model):
  title        = models.CharField(max_length=200)
  mp3          = models.FileField(upload_to = u'talks/', max_length=200)

Вот моя форма:

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 нужны файловые объекты или имена файлов на диске (я думаю, ) - первый случай (где загруженный файл больше, чем размер файла, обрабатываемого в памяти) работает нормально, но я не знаю, как обрабатывать InMemoryUploadedFile, которое я получаю в противном случае. Я пытался:

# 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())

Что-то не так с мутагеном, или я что-то не так делаю?

После ответа ребуса

Изменение параметра FILE_UPLOAD_HANDLERS на лету в моем классе ModelAdmin следующим образом:

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)

Получает следующую ошибку 500, когда я нажимаю «Отправить»:

Вы не можете установить обработчики загрузки после того, как загрузка была обработана.

хотя я делаю это как можно раньше!

Кроме того, я не уверен, что у меня есть метод save для возвращаемого объекта (я просмотрел dir(self.files['mp3'].file) и dir(self.files['mp3'])).


person Dominic Rodger    schedule 10.05.2010    source источник


Ответы (1)


Вы можете попробовать изменить свой FILE_UPLOAD_HANDLERS в таким образом, Django всегда использует обработчик временных файлов:

FILE_UPLOAD_HANDLERS по умолчанию:

("django.core.files.uploadhandler.MemoryFileUploadHandler",
 "django.core.files.uploadhandler.TemporaryFileUploadHandler",)

Таким образом, вы можете оставить только TemporaryFileUploadHandler, переопределив настройку в файле settings.py.

Изменить:

Гораздо проще, надо было подумать об этом в первую очередь :(:

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'])}

Таким образом вы можете сохранить InMemoryUploadedFile на диск, а затем использовать путь к этому файлу для работы с mutagen.

Изменить:

То же самое без экземпляра моделей.

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))

Обратите внимание, что он сохраняет файл в MEDIA_ROOT, когда я пытаюсь сохранить его в другом месте, я получаю SuspiciousOperation, поскольку есть ограничения на то, где вы можете писать... Вы должны удалить этот файл после его изучения, я думаю, настоящий файл будет на вашей модели...

path = default_storage.delete('tmp/somename.mp3')
person Davor Lucic    schedule 10.05.2010
comment
Это немного сложно в моем сценарии, поскольку у меня действительно нет доступа (или, скорее, я не хочу использовать обезьяний путь) соответствующих представлений, которые являются администратором, добавляющим объект и изменяющим представления объектов. - person Dominic Rodger; 11.05.2010
comment
На самом деле вы можете подклассифицировать оба представления в своем ModelAdmin определении для этой модели docs.djangoproject.com/en/dev/ref/contrib/admin/#other-methods - person Davor Lucic; 11.05.2010
comment
@rebus - спасибо за помощь, но не повезло - смотрите мое редактирование. Любые другие идеи? - person Dominic Rodger; 11.05.2010
comment
@Dominic Rodger Я немного отредактировал ответ, это должно быть намного проще сделать, оказывается, не так просто опередить защиту csrf вокруг представлений администратора (которые обращаются к request.POST), чтобы изменить upload_handlers . - person Davor Lucic; 11.05.2010
comment
@rebus - отлично - большое спасибо за помощь в этом! У меня еще не было возможности попробовать, но я дам вам знать, когда у меня будет! - person Dominic Rodger; 11.05.2010
comment
@rebus - ваше отредактированное решение не будет работать (вы не можете получить доступ к Talk.mp3, кроме как через экземпляр Talk) - я только что пошел и отключил MemoryFileUploadHandler - я возьму на себя загрузку файлов меньшего размера ради моего здравомыслия на данный момент. - person Dominic Rodger; 12.05.2010
comment
@Dominic Rodger не получил уведомления о вашем комментарии. Вот еще один пример с использованием механизма хранения напрямую... кроме этого, я в тупике... - person Davor Lucic; 13.05.2010
comment
@rebus - я объявил награду за этот вопрос, которую я намерен присудить вам, как только мне будет позволено поблагодарить вас за всю вашу помощь. Я попробую default_storage сегодня вечером, но если это не сработает, я буду рад оставить MemoryFileUploadhandler выключенным. Спасибо еще раз! - person Dominic Rodger; 13.05.2010