如何在Django项目实现PDF/Doc文件上传下载?求Admin/模板简化方案
简便实现Django目录文件下载的方案
嘿,我之前也做过类似的需求,你现在写的单个文件下载视图确实能跑,但用Django Admin或者优化前端的方式,能省不少重复代码,还更易维护!下面给你两个实用的方案:
方案一:用Django Admin管理可下载目录(自动打包成ZIP)
这个方案最适合管理员上传/维护目录,用户直接下载整个目录的压缩包,不用手动处理单个文件。
步骤1:创建模型管理目录元数据
首先定义一个模型,用来记录目录的基本信息(比如名称、描述、存储路径):
# models.py from django.db import models class DownloadableDirectory(models.Model): name = models.CharField(max_length=255, verbose_name="目录名称") description = models.TextField(blank=True, verbose_name="目录描述") directory_path = models.CharField(max_length=500, verbose_name="媒体目录路径") # 示例值:"downloads/brochures/" created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return self.name
步骤2:注册到Django Admin
把这个模型加到Admin里,管理员就能直接维护目录信息了:
# admin.py from django.contrib import admin from .models import DownloadableDirectory admin.site.register(DownloadableDirectory)
步骤3:写一个自动打包ZIP的视图
不用再写单个文件的逻辑,直接把指定目录打包成ZIP返回给用户:
# views.py import os import zipfile from django.http import HttpResponse from django.conf import settings from .models import DownloadableDirectory def download_directory(request, dir_id): dir_obj = DownloadableDirectory.objects.get(id=dir_id) # 拼接完整目录路径(基于MEDIA_ROOT) full_dir_path = os.path.join(settings.MEDIA_ROOT, dir_obj.directory_path) # 创建临时ZIP文件 response = HttpResponse(content_type='application/zip') response['Content-Disposition'] = f'attachment; filename="{dir_obj.name}.zip"' with zipfile.ZipFile(response, 'w') as zipf: for root, dirs, files in os.walk(full_dir_path): for file in files: file_path = os.path.join(root, file) # 计算ZIP内的相对路径,避免把整个服务器路径加进去 arcname = os.path.relpath(file_path, full_dir_path) zipf.write(file_path, arcname) return response
步骤4:配置URL
把视图加到URLconf里:
# urls.py from django.urls import path from .views import download_directory urlpatterns = [ # ... 其他URL path('download/directory/<int:dir_id>/', download_directory, name='download_directory'), ]
管理员只需要把目录放到MEDIA_ROOT下的对应路径,然后在Admin里添加一条记录,用户就能通过链接下载整个ZIP包了!
方案二:前端直接列出目录文件,支持单个下载
如果用户需要单独下载目录里的某个文件,结合Django的媒体文件配置,前端模板就能直接生成下载链接,几乎不用写额外视图。
步骤1:配置媒体文件访问
确保settings.py里已经配置了媒体文件的URL和路径:
# settings.py MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_URL = '/media/'
然后在根URLconf里添加媒体文件的访问路由:
# root urls.py from django.conf import settings from django.conf.urls.static import static urlpatterns = [ # ... 其他URL ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
步骤2:写视图获取目录下的文件列表
# views.py import os from django.conf import settings from django.shortcuts import render def download_page(request, dir_path): full_dir_path = os.path.join(settings.MEDIA_ROOT, dir_path) # 获取目录下的所有文件(可根据需求调整是否包含子目录) files = [f for f in os.listdir(full_dir_path) if os.path.isfile(os.path.join(full_dir_path, f))] # 生成每个文件的下载URL file_urls = [f"{settings.MEDIA_URL}{dir_path}/{f}" for f in files] return render(request, 'download_page.html', { 'dir_name': dir_path.split('/')[-1], 'file_list': zip(files, file_urls) })
步骤3:前端模板渲染下载链接
<!-- templates/download_page.html --> <h1>下载 {{ dir_name }}</h1> <ul> {% for file, url in file_list %} <li><a href="{{ url }}" download="{{ file }}">{{ file }}</a></li> {% endfor %} </ul>
这样用户就能在页面上看到目录里的所有文件,点击直接下载,完全不用像之前那样写单个文件的视图!
额外优化:用django-sendfile2简化单个文件下载
如果还是需要处理单个文件的下载,用django-sendfile2能省去手动打开文件的代码,安装后直接这样写:
# views.py from django_sendfile import sendfile def brochure(request): filename = 'kastom_profile.pdf' return sendfile(request, filename, attachment=True, attachment_filename='kastom_profile.pdf')
是不是比原来的代码简洁多了?
内容的提问来源于stack exchange,提问作者Dennis Gathagu
相关产品推荐
相关产品推荐

