django - 如何在生产中提供媒体文件
问题描述
我有一个 Django 项目,它向用户发送带有附加 pdf 的自动电子邮件。目前,我只有一个普通/media/
文件夹,其中包含代码指向的 pdf。这在开发中有效,但在生产中引发服务器错误。
我的问题是如何media
在生产中服务器文件?我已经阅读了很多关于它的内容,但找不到我想要的确切内容。
我collectstatic
在适用于静态文件的生产环境中使用,我希望media
文件有类似的东西。
网址
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('page.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
设置
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static_files')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, "static_media")
views.py(发送文件)
file_path = os.path.join(settings.STATIC_ROOT+'\\pdf\\free_pdf.pdf')
...
msg.attach_file(file_path)
乘客.wsgi
import os
import sys
sys.path.append(os.getcwd())
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
import django.core.handlers.wsgi
from django.core.wsgi import get_wsgi_application
from whitenoise import WhiteNoise
SCRIPT_NAME = os.getcwd()
SCRIPT_NAME = '' #solution for damn link problem
class PassengerPathInfoFix(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
from urllib.parse import unquote
environ['SCRIPT_NAME'] = SCRIPT_NAME
request_uri = unquote(environ['REQUEST_URI'])
script_name = unquote(environ.get('SCRIPT_NAME', ''))
offset = request_uri.startswith(script_name) and len(environ['SCRIPT_NAME']) or 0
environ['PATH_INFO'] = request_uri[offset:].split('?', 1)[0]
return self.app(environ, start_response)
application = get_wsgi_application()
application = PassengerPathInfoFix(application)
application = WhiteNoise(application, root='/home/mysite/mysite/static_files')
(这段代码来自我放弃媒体文件夹并试图将其与我的静态文件一起提供时)
我的项目结构:
|project
|__app
|__static
| |__app
| |__style.css
|__media
| |__app
| |__pdfToBeSent
|__static_files (generated by collectstatic)
|__media_files (i created this)
collectstatic 也不会将我的项目媒体文件复制到media_files
中,我自己一直在复制它们(对此不确定)。
我还尝试将媒体文件移动到项目中的每个可能位置
我还在为我的静态文件提供白噪声服务。
谢谢你。
解决方案
由于我处于类似情况(在同一主机上,A2Hosting),我将尝试分享我对问题的理解以及我选择的解决方案。
请原谅我,如果我在这个演示文稿中显得冒昧,我只是试图追溯所有代表导致我找到这个解决方案的思想流的点。
一个小前提:如果使用“媒体文件”您打算使用多媒体文件,例如图像等,我认为您不应该使用 Django 媒体文件夹,因为它旨在为用户上传的文件提供服务。
不知道您的 PDF 是否确实由某些用户上传,无论如何我都会尝试公开我的解决方案。
在生产环境中,Django 不会提供静态和媒体文件。
对于前者,我也使用了 WhiteNoise,而对于后者,方法不同(至少在共享托管基础上)。
当我们在settings.py中设置Debug = False时,我怀疑与 Django 项目一起创建的媒体文件夹变得有些不可读/不可访问(我无法判断是由 Django 之手还是托管者之手,或者是连词两者中)。
官方处理媒体文件的方法确实是依赖外部存储服务(如 Amazon S3),但这种方案不适合预算有限的场景。
在我的情况下,我让 Django 应用程序在与我的主域相关的子域上运行。
主域:www.mydomain.com
应用域:subdomain.mydomain.com
保留使用 Django 项目创建的媒体文件夹,我在以下 unix 路径中创建了另一个文件夹:
/home/A2hosting_username/subdomain.mydomain.com/media
然后,在settings.py 中,我将 MEDIA_ROOT 变量从:
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
至:
MEDIA_ROOT = '/home/A2hosting_username/subdomain.mydomain.com/media'
之后,在用于定义数据库并与之交互的model.py类中,我以这种方式指定了上传媒体(在我的情况下为视频)的路径:
class Video(models.Model):
name = models.CharField(max_length=50)
path = models.FileField(upload_to="../media/videos", null=True, verbose_name="")
由于我们无权访问 Apache 配置文件,因此可以通过以下方式编辑.htaccess文件(相对于subdomain.mydomain.com),以防止浏览器在上传文件时“超时”有点重:
<ifModule mod_headers.c>
Header set Connection keep-alive
</ifModule>
我希望这能有所帮助。