如何向Django应用上传新网页并实现静态项目访问功能
实现方案
1. 基础配置调整
首先明确Django的目录分工:templates目录仅用于存放需要Django模板引擎渲染的模板文件,独立JS项目的静态资源属于可公开访问的内容,应该通过Django的媒体文件体系处理,不要和站点本身的静态资源、模板文件混存,这也是你之前放在templates目录下资源加载失败的核心原因。
首先修改settings.py配置:
# 其他配置保持不变 MEDIA_URL = '/media/' # 上传的所有项目都会存在这个目录下 MEDIA_ROOT = BASE_DIR / 'media'
然后在项目根目录的urls.py中添加媒体文件访问路由(开发环境生效,生产环境建议用Nginx直接代理):
from django.conf import settings from django.conf.urls.static import static urlpatterns = [ # 你原有路由保持不变 ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
2. 设计项目存储模型
在你对应应用的models.py中新增项目存储模型,支持上传zip压缩包(后台无法直接上传文件夹,要求上传前将项目所有文件打包为zip即可):
from django.db import models from django.utils.text import slugify import zipfile import os from django.conf import settings class JSProject(models.Model): name = models.CharField("项目名称", max_length=100) slug = models.SlugField("访问路径标识", unique=True, blank=True) project_zip = models.FileField("项目压缩包", upload_to="project_zips/") extract_path = models.CharField("解压后路径", max_length=200, blank=True) def save(self, *args, **kwargs): # 自动生成slug if not self.slug: self.slug = slugify(self.name) super().save(*args, **kwargs) # 上传后自动解压 if self.project_zip and not self.extract_path: extract_dir = os.path.join(settings.MEDIA_ROOT, 'js_projects', self.slug) os.makedirs(extract_dir, exist_ok=True) # 解压zip with zipfile.ZipFile(self.project_zip.path, 'r') as zip_ref: # 安全校验:过滤路径穿越和非允许后缀的文件 allowed_suffixes = {'.html', '.css', '.js', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.woff', '.woff2', '.ttf'} for file in zip_ref.namelist(): # 禁止路径穿越 if '..' in file or file.startswith('/'): continue # 校验后缀 if os.path.splitext(file)[1].lower() not in allowed_suffixes: continue zip_ref.extract(file, extract_dir) self.extract_path = f'js_projects/{self.slug}' super().save(update_fields=['extract_path']) def __str__(self): return self.name
写完模型后执行python manage.py makemigrations和python manage.py migrate生成数据库表,再把这个模型注册到admin.py里就可以在后台上传项目了。
3. 配置访问路由和视图
首先新增视图函数,处理项目访问请求:
from django.http import HttpResponse, Http404 from django.conf import settings import os import mimetypes from .models import JSProject def serve_js_project(request, project_slug, file_path=''): # 先找到对应项目 try: project = JSProject.objects.get(slug=project_slug) except JSProject.DoesNotExist: raise Http404("项目不存在") # 没有指定文件时默认返回index.html if not file_path: file_path = 'index.html' # 拼接完整文件路径 full_file_path = os.path.join(settings.MEDIA_ROOT, project.extract_path, file_path) # 校验文件是否存在、是否在允许的目录内(防止路径穿越) if not os.path.exists(full_file_path) or not full_file_path.startswith(os.path.join(settings.MEDIA_ROOT, project.extract_path)): raise Http404("资源不存在") # 读取文件并返回,设置正确的MIME类型 with open(full_file_path, 'rb') as f: content = f.read() content_type, _ = mimetypes.guess_type(full_file_path) return HttpResponse(content, content_type=content_type)
然后在urls.py中添加对应路由:
urlpatterns = [ # 原有路由保持不变 path('projects/<slug:project_slug>/', serve_js_project, name='js_project_root'), path('projects/<slug:project_slug>/<path:file_path>', serve_js_project, name='js_project_file'), ]
注意事项
- 生产环境请配置Nginx直接代理
/media/js_projects/路径,不需要经过Django处理,性能和安全性更高 - 可以根据需要调整模型中的允许文件后缀,避免上传恶意可执行文件
- 上传的zip包根目录需要直接包含index.html,不要嵌套多层文件夹,否则访问时会找不到入口文件
- 如果需要手动迁移原有项目,直接将项目文件夹放入
media/js_projects/下对应slug的目录即可,不需要上传zip包
内容的提问来源于stack exchange,提问作者Micheal Nestor
相关产品推荐
相关产品推荐

