Django FileField (или ImageField) метод open() возвращает None для допустимого файла?
позвольте мне сказать следующее:
model.py:
class Task(models.Model):
...
seq_file = models.FileField(upload_to='files/', blank=True, null=True)
...
ajax.py(я использую dajaxice, но это не имеет значения):
...
def startTask(request, name):
task = Task.objects.get(task_name=name)
data = task.seq_file.open()
filename = os.path.join(settings.MEDIA_ROOT ,task.seq_file.name)
if not os.path.isfile(filename):
raise Exception, "file " + filename + " not found."
sequences = parser.parse(data.read())
...
это возвращает:
File "/home/mnowotka/Dokumenty/MgrFuncAdnot/app/django-gui/src/gui/ajax.py", line 43, in startTask
sequences = parser.parse(data.read())
AttributeError: 'NoneType' object has no attribute 'read'
а
...
def startTask(request, name):
task = Task.objects.get(task_name=name)
filename = os.path.join(settings.MEDIA_ROOT ,task.seq_file.name)
if not os.path.isfile(filename):
raise Exception, "file " + filename + " not found."
data = open(filename)
sequences = parser.parse(data.read())
...
работает отлично!
Почему?
(Я использую django 1.3)
Ответы
Ответ 1
потому что открытый метод моделей. FileField ничего не возвращает
вы можете просто использовать:
task.seq_file.read()
и вам не нужно рассчитывать путь к файлу для проверки наличия файла. вы можете использовать task.seq_file.path:
if not os.path.isfile(task.seq_file.path):
....
Ответ 2
A FileField
даст вам файл-подобный объект, и нет необходимости называть open() на нем. В вашем примере просто позвоните task.seq_file.file
.
Почему? Существует много резервных копий для FileField
, и многие из них не поддерживаются файлом на диске (например, для хранения S3). Наверное, поэтому в документации говорится, что он возвращает файл-подобный объект, а не файл. Для некоторых видов хранения "открытый" метод не имеет смысла.
Ответ 3
В случае сомнений проверьте код. Здесь выдержка из django.db.models.fields.files
:
def open(self, mode='rb'):
self._require_file()
self.file.open(mode)
# open() doesn't alter the file contents, but it does reset the pointer
open.alters_data = True
Итак, в случае FileField
, open
снова откроет файл, используя указанный режим. Затем, как только вы вызываете open
, вы можете продолжать использовать методы типа read
с использованием вновь примененного режима.
Ответ 4
Удивительно, но django.db.models.fields.files
не использует метод file.storage.exists()
, поэтому мне пришлось реализовать мою собственную небольшую функцию, чтобы иметь совместимую проверку на совместимость с файлами для фактического существования физического файла:
# Check whether actual file of FileField exists (is not deleted / moved out).
def file_exists(obj):
return obj.storage.exists(obj.name)