Tastypie中的FileField

时间:2012-02-26 01:31:53

标签: 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 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。我怎么做?任何代码片段都表示赞赏。

谢谢

2 个答案:

答案 0 :(得分:4)

首先确定如何通过API公开文件的URL方案。您不需要文件或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 /

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

GET ... / api / foomodel / 3 / download /

返回: ...实际文件的内容......

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

答案 1 :(得分:0)

在FileField上唯一的转换tastypie就是在你返回的内容上查找'url'属性,如果它存在则返回它,否则它将返回字符串化对象,正如你所注意到的只是文件名。

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

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