2012-02-23 12 views
18

Ujmę to tak:Django FileField (lub ImageField) metoda open() zwraca None dla poprawnego pliku?

model.py:

class Task(models.Model): 
    ... 
    seq_file = models.FileField(upload_to='files/', blank=True, null=True) 
    ... 

ajax.py (używam dajaxice ale to nie ma znaczenia):

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

Powrócisz :

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' 

ale:

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

działa idealnie! Dlaczego?

(używam Django 1.3)

Odpowiedz

25

ponieważ otwarta metoda models.FileField niczego nie

powrócić można po prostu użyć:

task.seq_file.read() 

i nie trzeba obliczać ścieżkę pliku do sprawdzenia, czy plik istnieje. można użyć task.seq_file.path:

if not os.path.isfile(task.seq_file.path): 
    .... 
+12

Jaki jest więc cel FileField open()? – mnowotka

+17

Niestety dokumentacja Django jest obecnie myląca: "Zachowuje się jak standardowa metoda open() Pythona ..." - https: //docs.djangoproject.com/en/1.4/ref/models/fields/# filefield-and-fieldfile Nie, zwracanie Brak po wykonaniu tajemniczej wewnętrznej otwartej operacji nie jest standardowym zachowaniem w języku Python. –

+1

powinien zgłosić problem w tej sprawie. – laike9m

7

FileField daje obiekt plikopodobny i nie ma potrzeby, aby zadzwonić open() na nim. W twoim przykładzie wystarczy zadzwonić pod numer task.seq_file.file.

Dlaczego tak jest? Istnieje wiele mechanizmów przechowywania danych dla FileField, a wiele z nich nie jest wspieranych przez plik na dysku (na przykład pamięć S3). Chyba dlatego dokumentacja mówi, że zwraca obiekt podobny do pliku, a nie plik. W przypadku niektórych rodzajów pamięci metoda "otwarta" nie ma sensu.

+1

Ale według django dokumentacji FileField jest proxy plik i mogę odwołać się do tego obiektu. Nie otrzymałem nawet informacji o nie zdefiniowanej metodzie, więc jest tam, prawda? Czy to błąd, czy po prostu czegoś nie rozumiem? – mnowotka

+2

@mnowotka: jest tam, ale nigdy go nie użyłem, FileField da ci obiekt podobny do pliku (już "otwarty"). –

+0

należy pamiętać, że FileField niekoniecznie jest wspierany przez plik na dysku (S3, inne rodzaje przechowywania w chmurze) –

3

W przypadku wątpliwości, należy sprawdzić kod. Oto fragment z django.db.models.fields.files:

def open(self, mode='rb'): 
    self._require_file() 
    self.file.open(mode) 
# open() doesn't alter the file's contents, but it does reset the pointer 
open.alters_data = True 

Tak więc, w przypadku FileField, open ponownie otwiera plik przy użyciu określonego trybu. Następnie, po wywołaniu open, można nadal używać metod takich jak read przy użyciu nowo zastosowanego trybu.

0

Niespodziewanie jednak django.db.models.fields.files nie wykorzystuje file.storage.exists() metodę więc musiałem realizować własną małą funkcję mieć przekrój pamięci kompatybilny czek na rzeczywistej fizycznej egzystencji Plik:

# Check whether actual file of FileField exists (is not deleted/moved out). 
def file_exists(obj): 
    return obj.storage.exists(obj.name) 
Powiązane problemy