如何返回通过django中的视图的静态文件?
Posted
技术标签:
【中文标题】如何返回通过django中的视图的静态文件?【英文标题】:How to return static files passing through a view in django? 【发布时间】:2011-01-18 15:59:54 【问题描述】:我需要根据具体逻辑返回css文件和js文件。显然,静态服务不能满足我的需要。我有一个视图,它的渲染方法使用逻辑来找到正确的文件,但是我必须返回它。从技术上讲,我可以读取文件并将其填充到具有正确 mime 类型的 HttpResponse 对象中,但我想知道是否有更好的策略。 (如 php 中的 fpassthru())
【问题讨论】:
哪个没有执行你需要的,webserver静态文件服务,还是django.views.static.serve
?
其实是语法问题。是“两者都不是”还是“两者”?
嗯,这就是我有点困惑的地方。您看,在您的问题中,您说您基本上可以读取文件并将其填充到 HttpResponse 中。因此,我假设这些文件按原样(即:非动态生成)存在于您文件系统的某处。是什么阻止您直接使用网络服务器为它们提供服务?还是我错过了什么?
我猜两者都不是,两者都不是 :)
【参考方案1】:
这是我用的:
test_file = open('/home/poop/serve/test.pdf', 'rb')
response = HttpResponse(content=test_file)
response['Content-Type'] = 'application/pdf'
response['Content-Disposition'] = 'attachment; filename="%s.pdf"' \
% 'whatever'
return response
【讨论】:
我需要 open() 函数上的 'rb' 模式,否则这段代码会弄乱我的 pdf。这与 django/views/static.py 中使用的代码匹配。 在我看来,这会导致整个文件被加载到内存中。不是吗? @EmanuelePaolini:您可以将迭代器传递给HttpResponse
,我已经修改了答案以反映这一点。
谢谢!我用urllib2.urlopen(url_path).read()
替换open(path)
以允许通过视图,从外部站点提供pdf:[1] url = "https://s3.amazonaws.com/bucketname/path-to-external-file.pdf"
[2] import urllib2
[3] test_file = urllib2.urlopen(url).read()
[4] response = HttpResponse(content=test_file)
[5 ] response['Content-Type'] = 'application/pdf'
[6] response['Content-Disposition'] = 'attachment; filename="%s.pdf"' % 'whatever'
[7] return response
@EmanuelePaolini 下面由 Ignacio Vazquez-Abrams 给出更好的答案,使用迭代器以块的形式返回文件,而不是在内存中加载完整文件。【参考方案2】:
您使用的是什么网络服务器软件?
至少对于 Apache 和 nginx,有一个模块可以让您使用 X-SendFile
HTTP 标头。 NginX 网站说 Lighty 也可以做到这一点。
在你的包装视图中:
...
abspath = '/most_secret_directory_on_the_whole_filesystem/protected_filename.css'
response = HttpResponse()
response['X-Sendfile'] = abspath
response['Content-Type'] = 'mimetype/submimetype'
# or let your webserver auto-inject such a header field
# after auto-recognition of mimetype based on filename extension
response['Content-Length'] = <filesize>
# can probably be left out if you don't want to hassle with getting it off disk.
# oh, and:
# if the file is stored via a models.FileField, you just need myfilefield.size
response['Content-Disposition'] = 'attachment; filename=%s.css' \
% 'whatever_public_filename_you_need_it_to_be'
return response
然后你可以通过http://mysite.com/url_path/to/serve_hidden_css_file/
连接视图。
您可以在任何需要对用户不应直接访问的文件执行某些操作时使用它,例如限制谁可以访问它,或统计对它的请求以获取统计信息等。
对于 Apache:http://tn123.ath.cx/mod_xsendfile/ 对于 NginX:http://wiki.nginx.org/NginxXSendfile
【讨论】:
【参考方案3】:为什么不在视图中使用 Django 静态文件
from django.contrib.staticfiles.views import serve
...
def view_function(request):
return serve(request, 'absolute_path_to_file_name')
【讨论】:
docs 说:“警告。此视图仅在 DEBUG 为 True 时才有效。那是因为此视图效率极低且可能不安全。这仅用于本地开发,绝不应该用于用于生产。” 我只是想要它。多谢。 @PhilippZedler 没问题,我们可以在生产中配置这些文件。但是在开发中提供像 /manifest.json 和 /servicewoker.js 这样的静态文件,我认为这是最好的方法。 但它显示 SuspiciousFileOperation 错误 它只允许从项目中的静态文件夹中提供文件。使用 (from django.views.static import serve) ,并将 document_root 参数添加到函数中。【参考方案4】:为什么不将HttpResponseRedirect
返回到正确静态文件的位置?
【讨论】:
因为文件不能直接访问。【参考方案5】:直接从视图提供文件非常慢。如果您正在寻找正常的文件服务,请参阅此问题:Having Django serve downloadable files
通过视图非常轻松地提供文件(例如出于调试目的)继续阅读。
# In your urls.py:
url(r'^test-files/(?P<name>.+)/$', views.test_files, name='test_files'),
# In your views.py:
from django.http.response import HttpResponse
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt # (Allows file download with POST requests, can be omitted)
def test_files(request, name):
if name == "myxml":
fsock = open("/djangopath/data/static/files/my.xml", "rb")
return HttpResponse(fsock)
这允许您从以下位置下载文件:http://127.0.0.1:8080/app/test-files/myxml/
【讨论】:
【参考方案6】:将迭代器(例如open()
的结果)传递给HttpResponse
构造函数。
【讨论】:
【参考方案7】:您可以在视图中使用以下代码:注意:在此函数中,我返回图像,但您可以根据需要返回所有内容并设置 context_type
from django.http import HttpResponse,Http404
import os
def img_finder(request, img_name):
try:
with open(os.path.dirname(os.path.abspath(__file__)) + '/static/img/' + img_name, 'rb') as f:
return HttpResponse(f.read(), content_type="image/jpeg")
except IOError:
raise Http404
【讨论】:
【参考方案8】:这是最简单有效的方法。
app/urls.py
from django.urls import re_path
from app import views
urlpatterns = [
re_path(r'^(?P<public_url>.*)$', views.public, name="public"),
]
警告:将 URL 模式放在末尾em>
app/views.py
import os
from django.conf import settings
from django.views.static import serve
def public(request, public_url):
public_folder = os.path.join(str(settings.BASE_DIR), 'folder_path')
return serve(request, public_url, document_root=public_folder)
【讨论】:
【参考方案9】:使用 django 提供静态内容应该是浪费(更不用说,慢了几个数量级)。
我宁愿将视图转换为上下文处理器,并使用模板中的变量来查找要包含的块。
【讨论】:
这正是我想要摆脱的。我已经包含了这些东西,结果 css 和 js 文件被硬编码到了 html 文件中,从而防止了任何形式的缓存(因为整个页面被认为发生了变化)。我希望能够运送 js 和 css,但由于这次运送取决于我的应用程序可用的插件,因此我需要在运送文件之前执行一些逻辑。 你的意思是阻止任何形式的 Django 缓存?因为让 css & js 包含硬编码到模板中不会阻止用户的浏览器缓存它们。我不清楚实际问题是什么。由于动态包含,听起来您在缓存整个页面时遇到了麻烦。为什么不缓存页面的其余部分并让浏览器/您的网络服务器完成其余部分(无论如何这是它的工作)? 在真正回答之后,这将是一个很好的评论或警告。以上是关于如何返回通过django中的视图的静态文件?的主要内容,如果未能解决你的问题,请参考以下文章