如何将JSON文件的内容放入响应中

5

我在电脑上有一个文件,我试图从django视图中将其作为JSON提供。

def serve(request):
    file = os.path.join(BASE_DIR, 'static', 'files', 'apple-app-site-association')
    response = HttpResponse(content=file)
    response['Content-Type'] = 'application/json'

我得到的是文件路径,当浏览URL时返回。
/Users/myself/Developer/us/www/static/files/apple-app-site-association

这里我做错了什么?

os.path.join 返回一个字符串(路径)。 - Emile Bergeron
@EmileBergeron那么我怎么获取文件的内容呢?我以为content=file就可以了。 - qarthandso
1
你将一个字符串放在变量 file 中,所以 content=file 将该字符串作为响应的内容。搜索如何使用Python读取文件。 - Emile Bergeron
“static” 是您的静态存储目录吗? - dhke
如果你碰巧只是想提供一个文件目录,使用python有一种非常简单的方法:进入要提供服务的目录,然后运行 python -m SimpleHTTPServer <port>...虽然有很多限制,但如果你已安装了python,它只需要几秒钟的时间。从Web浏览器中,您将能够导航和下载。 - s g
2个回答

5

os.path.join返回一个字符串,这就是为什么您在响应内容中得到了路径。您需要先读取该路径下的文件。

对于静态文件

如果文件是静态的并且在磁盘上,您可以直接使用Web服务器返回它,而无需使用Python和Django。如果需要身份验证才能下载文件,则仍然可以使用Django处理,并返回X-Sendfile标头(这取决于Web服务器)。

提供静态文件是Web服务器的工作,Nginx和Apache非常擅长此项工作,而Python和Django是处理应用程序逻辑的工具。

读取文件的最简单方法

def serve(request):
    path = os.path.join(BASE_DIR, 'static', 'files', 'apple-app-site-association')
    with open(path , 'r') as myfile:
        data=myfile.read()
    response = HttpResponse(content=data)
    response['Content-Type'] = 'application/json'

这受到了How do I read a text file into a string variable in Python的启发。

更高级的解决方案

请参见dhke的答案关于StreamingHttpResponse.

额外信息


不需要从内存中读取文件。文件对象是可迭代的,而StreamingHttpResponse会处理其余部分。 - dhke
如果文件是静态的且在磁盘上,根本不需要使用Python和Django。只需在Web服务器中进行配置即可。但由于OP不知道如何读取文件,我提供了最简单的方法来实现它。 - Emile Bergeron
1
那么 OP 就会学习了 ;-). 无论如何,谢谢你提醒我,一个简单的重定向可能就可以了。 - dhke
@dhke 我为你的答案添加了一个更高级的解决方案的链接。 - Emile Bergeron

4
如果您向HttpResponse提供一个字符串作为content,那么您告诉它将该字符串作为HTTP正文发送:serve that string

content应该是一个迭代器或者是一个字符串。如果它是一个迭代器,它应该返回字符串,并且这些字符串将被连接在一起形成响应的内容。如果它不是一个迭代器或字符串,当访问时它将被转换为一个字符串。

由于您似乎正在使用静态存储目录,因此最好使用staticfiles来处理内容。
from django.contrib.staticfiles.storage import staticfiles_storage
from django.http.response import StreamingHttpResponse

file_path = os.path.join('files', 'apple-app-site-association')

response = StreamingHttpResponse(content=staticfiles_storage.open(file_path))
return response

正如@Emile Bergeron的回答中所指出的那样,对于静态文件来说,这应该已经足够了,因为这些文件本来就可以从外部访问。因此,一个简单的重定向到 static(file_path) 应该也能实现目的(前提是您的Web服务器已正确配置)。

要服务于任何文件:

from django.contrib.staticfiles.storage import staticfiles_storage
from django.http.response import StreamingHttpResponse

file_path = ...

response = StreamingHttpResponse(content=open(file_path, 'rb'))
return response

请注意,从Django 1.10开始,文件句柄将自动关闭。

此外,如果该文件可以从您的Web服务器访问,请考虑使用django-sendfile,这样文件内容就不需要通过Django传输。


你为什么推荐使用StreamingHttpResponse而不是HttpResponse - qarthandso
1
@qarthandso 这取决于您的使用情况。如果您使用 StreamingHttpResponse,则文件将逐块从文件系统中读取,因为它被写入客户端。根据我的经验,如果您使用 HttpResponse(例如 ETag 生成),您可能会在内存中结束文件。对于小文件:不必费心。 - dhke
1
@qarthandso,通过我的回答和他的回答,你已经拥有解决手头问题所需的一切。你应该考虑给其中一个点赞并接受它,以标记问题已得到解答。 - Emile Bergeron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接