You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django生产环境无需S3/FTP等服务如何托管媒体文件?

Django生产环境(RailwayApp)无第三方服务托管媒体文件方案

鉴于你无法使用S3/FTP等第三方服务、Whitenoise不支持媒体文件托管,且部署在RailwayApp,可接受安全妥协,以下是直接用Django自身能力托管媒体文件的方案,同时覆盖视图生成ZIP文件的处理:

一、基础配置与媒体文件服务视图

1. 配置媒体路径

在settings.py中设置媒体文件的存储目录和访问URL:

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

# 媒体文件存储目录
MEDIA_ROOT = BASE_DIR / 'media'
# 媒体文件访问URL前缀
MEDIA_URL = '/media/'

2. 编写媒体文件服务视图

创建一个视图直接读取媒体文件并返回响应,可根据需求选择是否添加简单验证(比如登录限制):

import os
from django.http import FileResponse, Http404
from django.conf import settings
from django.contrib.auth.decorators import login_required

# 若完全开放访问,可删除@login_required装饰器
@login_required(login_url='/login/')
def media_view(request, file_path):
    full_file_path = os.path.join(settings.MEDIA_ROOT, file_path)
    # 校验文件是否存在且为文件类型
    if not os.path.exists(full_file_path) or not os.path.isfile(full_file_path):
        raise Http404("文件不存在")
    # 返回文件响应,as_attachment=False表示直接在浏览器打开,True则触发下载
    return FileResponse(open(full_file_path, 'rb'), as_attachment=False)

3. 配置URL路由

在项目主urls.py中添加媒体文件的路由映射:

from django.urls import path
from .views import media_view

urlpatterns = [
    # 其他业务路由...
    path('media/<path:file_path>', media_view, name='media'),
]

二、处理视图生成的ZIP文件

如果需要生成ZIP文件并提供访问,可选择两种方式:

方式1:直接返回ZIP下载响应

无需保存ZIP到服务器,生成后直接通过响应返回给用户:

import zipfile
from io import BytesIO
from django.http import FileResponse
from django.conf import settings

def generate_and_download_zip(request):
    # 准备要压缩的文件列表(示例)
    target_files = [
        settings.MEDIA_ROOT / 'report.pdf',
        settings.MEDIA_ROOT / 'data.csv'
    ]
    
    # 在内存中创建ZIP文件
    zip_buffer = BytesIO()
    with zipfile.ZipFile(zip_buffer, 'w') as zipf:
        for file in target_files:
            if file.exists():
                zipf.write(file, arcname=file.name)
    zip_buffer.seek(0)
    
    # 返回下载响应
    return FileResponse(zip_buffer, as_attachment=True, filename='archive.zip')

方式2:保存ZIP到媒体目录并提供永久访问链接

如果需要用户后续能再次访问该ZIP,可将其保存到MEDIA_ROOT,然后通过之前配置的媒体视图提供访问:

import zipfile
from datetime import datetime
from django.http import HttpResponse
from django.conf import settings

def generate_and_store_zip(request):
    target_files = [
        settings.MEDIA_ROOT / 'report.pdf',
        settings.MEDIA_ROOT / 'data.csv'
    ]
    # 生成唯一文件名避免冲突
    zip_filename = f'archive_{datetime.now().strftime("%Y%m%d%H%M%S")}.zip'
    zip_full_path = settings.MEDIA_ROOT / zip_filename
    
    # 创建并保存ZIP文件
    with zipfile.ZipFile(zip_full_path, 'w') as zipf:
        for file in target_files:
            if file.exists():
                zipf.write(file, arcname=file.name)
    
    # 返回访问链接
    media_url = f'{settings.MEDIA_URL}{zip_filename}'
    return HttpResponse(f'<a href="{media_url}">点击下载生成的ZIP文件</a>')

三、RailwayApp部署注意事项

Railway的默认文件系统是临时的,重启后未挂载持久卷的目录会丢失文件,因此需要配置持久卷:

  1. 进入Railway控制台的项目页面,点击「Add Volume」添加持久卷
  2. 设置挂载路径为你的MEDIA_ROOT路径(例如/app/media,需与settings.py中的路径一致)
  3. 确保启动命令使用生产服务器(如gunicorn your_project.wsgi:application),Django开发服务器虽能处理媒体文件,但性能和稳定性不足

安全妥协说明

  • 直接用Django视图服务媒体文件,性能远低于Nginx等专业静态文件服务器,高流量场景下可能出现瓶颈
  • 若开放无验证访问,存在文件泄露风险(攻击者可通过猜测文件名下载敏感文件),建议至少添加登录验证或限制可访问的文件类型

内容的提问来源于stack exchange,提问作者Tanjim Hudai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 09:37:18