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

Django用户上传加密文件下载及下载后删除功能问题求助

Django文件加密网站问题修复方案

问题说明

基于Django开发的文件加密解密网站,已实现文件上传加密功能,但存在两个问题:

  • 无法下载media目录中保存的加密文件
  • 需要实现文件下载完成后自动删除的功能

现有代码

models.py

from django.db import models
import os

class Fileupload(models.Model):
    file = models.FileField(upload_to='media')
    date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.file  # 错误:返回FileField对象而非字符串
    def filename(self):
        return os.path.basename(self.file.name)

views.py

from msilib.schema import File
from urllib import response
from django.shortcuts import render,HttpResponse
from .models import Fileupload
from .encryptfile import encrypt

import os
from cryptography.fernet import Fernet
import mimetypes

def base(request):
    if request.method == 'POST':
        file2 = request.FILES["file"]
        document = Fileupload.objects.create(file=file2)
        document.save()
        fname = Fileupload.filename(document)
        global path1 
        path1 = "media/"+fname

        # 加密逻辑存在错误
        key = Fernet.generate_key()
        with open("thekey.key","wb") as thekey:
            thekey.write(key)
        
        with open(path1, 'rb') as file:
            original = file2.read()  # 错误:应读取本地保存的文件而非上传的临时文件
            
        encrypted = Fernet(key).encrypt(original)
        with open(path1, 'wb') as encrypted_file:
            encrypted_file.write(encrypted)
        
        return render(request,'download.html')
    else:
        return render(request, 'base.html')

def download(request):
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    # filename未定义
    filepath = BASE_DIR + '/media/' + filename
    path1 = open(filepath, 'r')  # 错误:二进制文件需用rb模式
    mime_type, _ = mimetypes.guess_type(filepath)
    response = HttpResponse(path, content_type=mime_type)  # 错误:变量名应为path1
    response['Content-Disposition'] = "attachment; filename=%s" % filename
    return render(request, response,'base.html')  # 错误:不应使用render返回文件响应

def decrypt(request):
    return render(request, 'decrypt.html')

urls.py

from django.contrib import admin
from django.urls import path
from Home import views
from django.conf.urls.static import static
from django.conf import settings

urlpatterns = [
    path('admin/', admin.site.urls),
    path('download',views.download,name='download'),
    path('decrypt',views.decrypt,name='decrypt'),
    path('',views.base,name='base'),
] + static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT) 

download.html

<section class="u-align-center u-clearfix u-image u-shading u-section-1" 
      src="static/img/bghack.jpg" data-image-width="7395" data-image-height="4933" id="sec-f710">
    <div class="u-clearfix u-sheet u-sheet-1">
        <h1 class="u-text u-text-default u-title u-text-1">ENCRYPTION OF FILES</h1>
        <p class="u-large-text u-text u-text-default u-text-variant u-text-2">The file has been encrypted. Download the file by clicking the button below.</p>
        {% if url %}
        <div class = "download">
            <a href="{{ url }}" type="button" download class="u-btn u-button-style u-palette-2-base u-btn-1">Download the file</a>
        </div>
        {% endif %}
    </div>
</section>

修复方案

1. 修复文件下载功能

核心修改点:

  • 移除全局变量,改用session传递文件ID
  • 修正文件读取模式为二进制rb
  • 直接返回HttpResponse作为文件响应
  • 修正加密逻辑中读取文件的错误

修改后的代码:

models.py(修正__str__方法)
from django.db import models
import os

class Fileupload(models.Model):
    file = models.FileField(upload_to='media')
    date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.file.name  # 返回文件路径字符串
    def filename(self):
        return os.path.basename(self.file.name)
views.py(重写base和download视图)
from django.shortcuts import render,HttpResponse
from .models import Fileupload

import os
from cryptography.fernet import Fernet
import mimetypes

def base(request):
    if request.method == 'POST':
        file2 = request.FILES["file"]
        document = Fileupload.objects.create(file=file2)
        document.save()
        fname = document.filename()
        file_path = document.file.path

        # 修正加密逻辑:读取本地已保存的文件
        key = Fernet.generate_key()
        with open("thekey.key","wb") as thekey:
            thekey.write(key)
        
        with open(file_path, 'rb') as file:
            original = file.read()
            
        encrypted = Fernet(key).encrypt(original)
        with open(file_path, 'wb') as encrypted_file:
            encrypted_file.write(encrypted)
        
        # 将文件ID存入session,供下载视图使用
        request.session['file_id'] = document.id
        # 传递文件名到下载页面
        return render(request,'download.html', {'file_name': fname})
    else:
        return render(request, 'base.html')

def download(request):
    # 从session获取文件ID
    file_id = request.session.get('file_id')
    if not file_id:
        return HttpResponse("无可用下载文件", status=404)
    
    try:
        document = Fileupload.objects.get(id=file_id)
        file_path = document.file.path
        
        # 二进制读取加密文件
        with open(file_path, 'rb') as f:
            content_type = mimetypes.guess_type(file_path)[0] or 'application/octet-stream'
            response = HttpResponse(f.read(), content_type=content_type)
            response['Content-Disposition'] = f'attachment; filename="{document.filename()}"'
            
            # 下载完成后自动删除文件及数据库记录
            def cleanup(response):
                if os.path.exists(file_path):
                    os.remove(file_path)
                document.delete()
                del request.session['file_id']  # 清除session中的文件ID
            
            response.close = cleanup
            return response
    except Fileupload.DoesNotExist:
        return HttpResponse("文件不存在", status=404)

def decrypt(request):
    return render(request, 'decrypt.html')
download.html(修改下载按钮路由)
<section class="u-align-center u-clearfix u-image u-shading u-section-1" 
      src="static/img/bghack.jpg" data-image-width="7395" data-image-height="4933" id="sec-f710">
    <div class="u-clearfix u-sheet u-sheet-1">
        <h1 class="u-text u-text-default u-title u-text-1">文件已加密完成</h1>
        <p class="u-large-text u-text u-text-default u-text-variant u-text-2">文件已加密,点击下方按钮下载。</p>
        <div class="download">
            <a href="{% url 'download' %}" class="u-btn u-button-style u-palette-2-base u-btn-1">下载文件</a>
        </div>
    </div>
</section>

2. 实现下载完成后自动删除

上述download视图中,通过给HttpResponse的close方法绑定清理函数,在响应完成(即文件下载完成)后自动执行以下操作:

  • 删除本地文件
  • 删除数据库中的Fileupload记录
  • 清除session中的文件ID,避免重复下载

内容的提问来源于stack exchange,提问作者NEERAJ S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 18:40:49