2012-02-26 36 views
1

我有一個模型,其中我提出在tastypie的API。我有一個存儲路徑的字段,我手動維護的文件(由於用戶沒有上傳文件,我沒有使用FileField)。這裏是一個模型的要點:的FileField在Tastypie

class FooModel(models.Model): 
    path = models.CharField(max_length=255, null=True) 
    ... 
    def getAbsPath(self): 
     """ 
     returns the absolute path to a file stored at location self.path 
     """ 
     ... 

這裏是我的tastypie配置:

class FooModelResource(ModelResource): 
    file = fields.FileField() 

    class Meta: 
     queryset = FooModel.objects.all() 

    def dehydrate_file(self, bundle): 
     from django.core.files import File 
     path = bundle.obj.getAbsPath()   
     return File(open(path, 'rb')) 

在文件領域的API這樣會返回一個文件的完整路徑。我希望tastypie能夠提供實際的文件或至少一個文件的URL。我怎麼做?任何代碼片斷,讚賞。

謝謝

回答

4

決定一個URL方案如何您的文件將通過API的第一個被曝光。你並不需要file或dehydrate_file(除非你想在Tastypie中更改模型本身的文件表示)。相反,只需在ModelResource上添加一個附加操作即可。例如:

class FooModelResource(ModelResource): 
    file = fields.FileField() 

    class Meta: 
     queryset = FooModel.objects.all() 

    def override_urls(self): 
     return [ 
      url(r"^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/download%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('download_detail'), name="api_download_detail"), 
      ] 

    def download_detail(self, request, **kwargs): 
     """ 
     Send a file through TastyPie without loading the whole file into 
     memory at once. The FileWrapper will turn the file object into an 
     iterator for chunks of 8KB. 

     No need to build a bundle here only to return a file, lets look into the DB directly 
     """ 
     filename = self._meta.queryset.get(pk=kwargs[pk]).file 
     wrapper = FileWrapper(file(filename)) 
     response = HttpResponse(wrapper, content_type='text/plain') #or whatever type you want there 
     response['Content-Length'] = os.path.getsize(filename) 
     return response 

GET .../API/foomodel/3/

返回: { ... '文件': '局部路徑/ FILENAME.EXT', ... }

GET .../API/foomodel/3 /下載/

返回: ...實際文件的內容...

或者,您可以在FooModel中創建一個非ORM子資源文件。您必須定義resource_uri(如何唯一標識資源的每個實例),並覆蓋dispatch_detail以完成上面的download_detail操作。

+0

哪裏'FileWrapper'從何而來? – 2012-11-26 03:00:02

+0

'從django.core.servers.basehttp進口FileWrapper' – astevanovic 2012-11-26 12:50:56

+0

這是否關閉文件句柄它被傳輸到客戶端後? – 2012-11-26 20:02:40

0

唯一的轉換tastypie不上的FileField是尋找一個「網址」你回報什麼屬性,並返回,如果它存在,否則將返回字符串化的對象,正如你已經注意到的只是文件名。

如果要返回該文件的內容作爲一個領域,你將需要處理的文件的編碼。您有幾種選擇:

  • 最簡單的:使用CharField和使用base64模塊從文件中讀取的字節轉換成字符串
  • 更普遍的,但在功能上等同的:寫一個知道的自定義tastypie串行如何打開File對象到其內容
  • 字符串表示重寫你的資源的get_detail功能服務只是用文件任何內容型爲宜,避免JSON/XML序列化的開銷。