如何从Django模型中安全下载用户已购买的图片或文件
可行方案:自定义带权限校验的下载视图
这是目前Django生态下最通用、安全度最高的私有文件下载实现方式,不需要依赖第三方未维护模块,所有权限逻辑完全可控。
步骤1:补充用户购买关联模型(未实现购买记录的情况下需要)
你需要先记录哪些用户购买了哪些图片,基础模型示例如下:
from django.db import models from django.contrib.auth.models import User from your_app.models import Pic class UserPurchase(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="purchases") pic = models.ForeignKey(Pic, on_delete=models.CASCADE) purchase_time = models.DateTimeField(auto_now_add=True) class Meta: unique_together = ('user', 'pic') # 避免重复记录同一用户的同一购买行为
步骤2:编写带权限校验的下载视图
这个视图会先校验用户登录状态、购买权限,校验通过后才返回文件下载响应,完全避免路径遍历风险:
from django.http import HttpResponse, Http404 from django.contrib.auth.decorators import login_required from django.conf import settings import os from your_app.models import Pic, UserPurchase @login_required # 强制要求用户登录才能访问下载接口 def download_pic(request, pic_id): # 校验请求的图片是否存在 try: pic = Pic.objects.get(id=pic_id) except Pic.DoesNotExist: raise Http404("请求的图片不存在") # 校验当前用户是否已购买该图片 if not UserPurchase.objects.filter(user=request.user, pic=pic).exists(): return HttpResponse("您未购买该图片,无权下载", status=403) # 构造文件路径返回下载响应 file_path = os.path.join(settings.MEDIA_ROOT, pic.image_files.name) if os.path.exists(file_path): with open(file_path, 'rb') as f: response = HttpResponse(f.read(), content_type="application/octet-stream") response['Content-Disposition'] = f'attachment; filename={os.path.basename(file_path)}' return response else: raise Http404("图片源文件不存在")
如果你的高清图片体积较大,可以改用StreamingHttpResponse替代普通HttpResponse,避免内存占用过高
步骤3:配置下载路由
在urls.py中添加对应路由,全程不会暴露文件实际存储路径:
from django.urls import path from your_app.views import download_pic urlpatterns = [ # 保留原有其他路由 path('download/pic/<int:pic_id>/', download_pic, name='download_pic'), ]
步骤4:修改单页模板的下载链接
在single_post_view.html中添加下载按钮,仅在用户已购买时显示:
{% if user.is_authenticated %} {% with user.purchases.all as purchases %} {% for purchase in purchases %} {% if purchase.pic.id == pic.id %} <a href="{% url 'download_pic' pic.id %}" class="download-btn">下载高清原图</a> {% endif %} {% endfor %} {% endwith %} {% endif %}
额外优化建议
- 生产环境并发较高的情况下,可以配合Nginx的
X-Accel-Redirect特性实现内部重定向,把文件传输压力交给Nginx处理,性能远高于Django直接返回文件,不需要依赖额外第三方模块,仅需修改下载视图的响应头即可。 - 可以给下载接口添加请求频率限制,避免恶意爬虫批量爬取已购买用户的文件。
内容的提问来源于stack exchange,提问作者Novartis Nk
相关产品推荐
相关产品推荐

