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

如何从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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 08:27:02