Python Tastypie中的文件字段

Python Tastypie中的文件字段,python,django,tastypie,Python,Django,Tastypie,我有一个模型,我正在用tastypie为其制作api。我有一个字段,用于存储手动维护的文件路径(我没有使用FileField,因为用户没有上载文件)。以下是模型的要点: class FooModel(models.Model): path = models.CharField(max_length=255, null=True) ... def getAbsPath(self): """ returns the absolute path

我有一个模型,我正在用tastypie为其制作api。我有一个字段,用于存储手动维护的文件路径(我没有使用
FileField
,因为用户没有上载文件)。以下是模型的要点:

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。我该怎么做?欢迎使用任何代码片段


谢谢

tastypie对文件字段所做的唯一转换是在返回的内容上查找“url”属性,并返回该属性,如果该属性存在,则它将返回字符串化的对象,正如您所注意到的,该对象就是文件名

如果要将文件内容作为字段返回,则需要处理文件的编码。您有几个选择:

  • 最简单:使用
    CharField
    并使用
    base64
    模块将从文件读取的字节转换为字符串
  • 更通用但功能相当:编写一个自定义的tastypi序列化程序,它知道如何将文件对象转换为其内容的字符串表示形式
  • 覆盖资源的
    get_detail
    函数,以使用任何适当的内容类型为文件提供服务,以避免JSON/XML序列化开销

tastypie对文件字段所做的唯一转换是在返回的内容上查找“url”属性,如果该属性存在,则返回字符串化的对象,正如您所注意到的,该对象就是文件名

如果要将文件内容作为字段返回,则需要处理文件的编码。您有几个选择:

  • 最简单:使用
    CharField
    并使用
    base64
    模块将从文件读取的字节转换为字符串
  • 更通用但功能相当:编写一个自定义的tastypi序列化程序,它知道如何将文件对象转换为其内容的字符串表示形式
  • 覆盖资源的
    get_detail
    函数,以使用任何适当的内容类型为文件提供服务,以避免JSON/XML序列化开销

决定一个URL方案,如何首先通过API公开文件。您实际上不需要file或deterhemate_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
类FooModelResource(ModelResource):
file=fields.FileField()
类元:
queryset=FooModel.objects.all()
def覆盖URL(自身):
返回[
url(r“^(?P%s)/(?P\w[\w/-]*)/下载%s$”%(self.\u meta.resource\u name,trailing\u slash()),self.wrap\u view('download\u detail'),name=“api\u download\u detail”),
]
def下载详细信息(自我、请求、**kwargs):
"""
通过TastyPie发送文件,而不将整个文件加载到
文件包装器将把文件对象变成一个
用于8KB块的迭代器。
不需要在这里构建一个bundle,只返回一个文件,让我们直接查看数据库
"""
filename=self.\u meta.queryset.get(pk=kwargs[pk]).file
包装器=文件包装器(文件名))
response=HttpResponse(包装器,content_type='text/plain')#或任何您想要的类型
响应['Content-Length']=os.path.getsize(文件名)
返回响应
获取…/api/foomodel/3/

返回: { ... 'file':'localpath/filename.ext', ... }

获取…/api/foomodel/3/下载/

返回: …实际文件的内容


或者,您可以在FooModel中创建一个非ORM子资源文件。您必须定义
resource\u uri
(如何唯一地标识资源的每个实例),并覆盖dispatch\u detail以执行上面的下载\u detail所做的操作。

确定一个URL方案,首先通过API公开您的文件。您实际上不需要file或deterhemate_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
类FooModelResource(ModelResource):
file=fields.FileField()
类元:
queryset=FooModel.objects.all()
def覆盖URL(自身):
返回[
url(r“^(?P%s)/(?P\w[\w/-]*)/下载%s$”%(self.\u meta.resource\u name,trailing\u slash()),self.wrap\u view('download\u detail'),name=“api\u download\u detail”),
]
def下载详细信息(自我、请求、**kwargs):
"""
通过TastyPie发送文件,而不将整个文件加载到
文件包装器将把文件对象变成一个
用于8KB块的迭代器。
不需要在这里构建一个bundle,只返回一个文件,让我们直接查看数据库
"""
filename=self.\u meta.queryset.get(pk=kwargs[pk]).file
包装器=文件包装器(文件名))
response=HttpResponse(包装器,content_type='text/plain')#或任何您想要的类型
响应['Content-Length']=os.path.getsize(文件名)
返回响应
获取…/api/foomodel/3/

返回: { ... 'file':'localpath/filename.ext', ... }

获取…/api/foomodel/3/下载/

返回: …实际文件的内容


或者,您可以在FooModel中创建一个非ORM子资源文件。您必须定义
资源\u uri
(如何唯一标识资源的每个实例),并覆盖dispatch_detail以执行上面的download_detail所做的操作。

FileWrapper从何而来?
从django.core.servers.basehttp导入FileWrapper
将文件传输到客户端后是否关闭文件句柄?不是直接关闭,而是本质上关闭。自从