2011-06-17 88 views
2

上註冊解壓縮的文件[我提前道歉這個問題的長度。]Django的:在本地磁盤

我使用Django 1.2.3-3 + squeeze1 Debian的擠壓。

我正在編寫一個應用程序,它將zip文件上傳到 臨時位置的磁盤,將它們解壓縮,然後將結果保存到 永久位置。解壓後的文件在解壓縮後會作爲名爲 FileUpload的類註冊到數據庫中。上傳的壓縮文件也對應於一個類, 但我會忽略這個問題的目的。 FileUpload看起來像這樣。

class FileUpload(models.Model): 
    folder = models.ForeignKey(FolderUpload, null=True, blank=True, related_name='parentfolder') 
    upload_date = models.DateTimeField(default=datetime.now(), blank=True, editable=False) 
    upload = models.FileField(upload_to=file_upload_path) 
    name = models.CharField(max_length=100) 
    description = models.CharField(blank=True, max_length=200) 

    def save(self): 
     if not self.id: 
      if self.folder == None: 
       pass 
      else: 
       self.path = self.folder.path 
     super(FileUpload, self).save() 

我還使用由

from django.forms import ChoiceField, Form, ModelForm 

class FileUploadForm(ModelForm): 
    class Meta: 
     model = FileUpload 

,是以磁盤上的解壓縮文件的函數定義的形式。將它們登記在 與數據庫,並將它們移動到正確的位置被稱爲 addFile。我以前使用這個:

def addFile(name, filename, description, content, folder_id=None): 
    #f = open(filename, 'r') 
    #content = f.read() 
    from forms import FileUploadForm 
    from django.core.files.uploadedfile import SimpleUploadedFile 
    if folder_id == None: 
     data = {'name':name, 'description':description} 
    else: 
     data = {'name':name, 'description':description, 'folder':str(folder_id)} 
    file_data = {'upload': SimpleUploadedFile(filename, content)} 
    ff = FileUploadForm(data, file_data) 
    try: 
     zf = ff.save(commit=False) 
     zf.save() 
    except: 
     raise RuntimeError, "Form error is %s."%(ff.errors) 
    return zf 

這個工作,但問題是,它傾倒整個文件到內存 。對於大文件,特別是Python並不知道 這是內存經濟性,這消耗了大量的內存。所以我 切換到這一點:

from django.core.files.uploadedfile import UploadedFile 

class UnzippedFile(UploadedFile): 

    def __init__(self, file, filepath, content_type='text/plain', charset=None): 
     import os 
     self.filepath = filepath 
     self.name = os.path.basename(filepath) 
     self.size = os.path.getsize(filepath) 
     self.content_type = content_type 
     self.charset = charset 
     super(UnzippedFile, self).__init__(file, self.name, content_type, self.size, charset) 

    def temporary_file_path(self): 
     """ 
     Returns the full path of this file. 
     """ 
     return self.filepath 

def addFile(filepath, description, file, folder_id=None): 
    import os, sys 
    from forms import FileUploadForm 
    from django.core.files.uploadedfile import UploadedFile 
    name = os.path.basename(filepath) 
    if folder_id == None: 
     data = {'name':name, 'description':description} 
    else: 
     data = {'name':name, 'description':description, 'folder':str(folder_id)} 
    file_data = {'upload': UnzippedFile(file, filepath)} 
    ff = FileUploadForm(data, file_data) 
    try: 
     zf = ff.save(commit=False) 
     zf.save() 
    except: 
     raise 
    return zf 

我被迫繼承UploadedFile,因爲沒有派生 類,已經在那裏(在 django/core/files/uploadedfile.py)似乎做我想要的。

temporary_file_path功能是存在的,因爲Django File Uploads docs

UploadedFile.temporary_file_path()

只有上傳到磁盤上都會有這樣的方法文件;它會返回臨時上傳文件的完整路徑 。

看來FileSystemStorage類會在 _save功能這個屬性如後文所述。

如果n是於zip存檔文件的相對路徑,那麼 用法

name = os.path.normpath(os.path.basename(n)) # name of file 
pathname = os.path.join(dirname, n) # full file path 
description = "from zip file '" + zipfilename + "'" # `zipfilename` is the name of the zip file 
fname = open(pathname) # file handle 
f = addFile(pathname, description, fname) 

這工作,但我通過代碼跟蹤,發現該代碼是 使用流,當明確在這種情況下 的最佳做法是將文件從臨時位置複製到永久位置 。有問題的代碼是 django/core/files/storage.py_save函數的 FileSystemStorage類。在_save,name是目標的相對路徑 ,而contentFile的對象。

def _save(self, name, content): 
    full_path = self.path(name) 
    directory = os.path.dirname(full_path) 
    [...] 
    while True: 
      try: 
       # This file has a file path that we can move. 
       if hasattr(content, 'temporary_file_path'): 
        file_move_safe(content.temporary_file_path(), full_path) 
        content.close() 

       # This is a normal uploadedfile that we can stream. 
       else: 
        # This fun binary flag incantation makes os.open throw an 
        # OSError if the file already exists before we open it. 
        fd = os.open(full_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, 'O_BINARY', 0)) 
        try: 
         locks.lock(fd, locks.LOCK_EX) 
         for chunk in content.chunks(): 
          os.write(fd, chunk) 
        finally: 
         locks.unlock(fd) 
         os.close(fd) 
      except OSError, e: 
       if e.errno == errno.EEXIST: 
        # Ooops, the file exists. We need a new file name. 
        name = self.get_available_name(name) 
        full_path = self.path(name) 
       else: 
        raise 
      else: 
       # OK, the file save worked. Break out of the loop. 
       break 

_save功能正在尋找屬性 temporary_file_path。我相信此代碼旨在通過 django/core/files/uploadedfile.py前面提到的temporary_file_path功能觸發 。然而,就是 實際上傳遞的類(對應於content參數)是<class 'django.db.models.fields.files.FieldFile'>,這裏是 屬性字典(content.__dict__)此對象的樣子:

{'_committed': False, 'name': u'foo', 'instance': <FileUpload: foo>, 
'_file': <UnzippedFile: foo (text/plain)>, 'storage':<django.core.files.storage.DefaultStorage object at 0x9a70ccc>, 
'field': <django.db.models.fields.files.FileField object at0x9ce9b4c>, 'mode': None} 

temporary_file_path連接到 UnzippedFile類,它位於_file數據成員內部。所以 content._file具有temporary_file_path屬性,而不是content 本身。

這是常規文件上傳的樣子。正如你所看到的,它是相似的。

[Fri Jun 17 08:05:33 2011] [error] type of content is <class 'django.db.models.fields.files.FieldFile'> 
[Fri Jun 17 08:05:33 2011] [error] {'_committed': False, 'name': u'behavior.py', 
            'instance': <FileUpload: b>, '_file': <TemporaryUploadedFile: behavior.py (text/x-python)>, 
            'storage': <django.core.files.storage.DefaultStorage object at 0xb8d7fd8c>, 
            'field': <django.db.models.fields.files.FileField object at 0xb8eb584c>, 'mode': None} 

這是我很難在任何一個細節的代碼怎麼會從 的FileUploadFormsaveStorage對象跟隨。 Django表格 特別是代碼很模糊。

無論如何,我的問題,畢竟這個設置是,如何/何時是第一個 選項下面,與​​應該被激活?我在 看到這裏不匹配。這是一個錯誤?任何人都可以澄清?

回答

0
if hasattr(content, 'temporary_file_path') 

由於您聲明內容沒有temporary_file_path標識符,因此以上內容永遠不會與此條件等同。然而,由於content._file也可以使用以下方法來得到你正在尋找

if hasattr(content, '_file'): 
    if hasattr(content._file,'temporary_file_path'): 
+0

是功能,我可以修改的存儲類來做到這一點,但我工作的假設類是指開箱即用,基本上,我想知道Django開發人員的想法。也許我錯過了一些東西。 – 2011-06-17 21:02:22