如何为Django数据库中存储的图片生成带有效期的访问URL
Django 实现有时效性的图片访问链接方案
1. 创建临时链接存储模型
你需要新增一个数据库模型,用来关联Photo表、存储链接校验凭证和过期时间:
import uuid from django.db import models from django.utils import timezone from datetime import timedelta # 引入你已经定义的Photo模型 from .models import Photo class TemporaryPhotoLink(models.Model): # 关联原图片表 photo = models.ForeignKey(Photo, on_delete=models.CASCADE, null=False, blank=False) # 唯一访问凭证,避免链接被遍历 access_token = models.UUIDField(default=uuid.uuid4, unique=True, editable=False) # 过期时间 expire_at = models.DateTimeField(null=False, blank=False) # 可选字段:控制是否单次访问后就失效,不需要可以删除 is_used = models.BooleanField(default=False) # 校验链接是否有效的方法 def is_valid(self): return not self.is_used and timezone.now() < self.expire_at # 快速生成临时链接的类方法 @classmethod def generate_for_photo(cls, photo, expire_seconds=500): expire_time = timezone.now() + timedelta(seconds=expire_seconds) return cls.objects.create(photo=photo, expire_at=expire_time)
执行python manage.py makemigrations和python manage.py migrate创建对应数据库表。
2. 配置临时链接生成逻辑
首先在项目urls.py中新增临时链接的路由规则:
from django.urls import path from . import views urlpatterns = [ # 你的其他路由 path('temp-photo/<uuid:token>/', views.temp_photo_access, name='temp_photo_access'), ]
需要生成链接时调用以下逻辑即可获得有效期500秒的访问地址:
from django.urls import reverse # 传入需要生成链接的Photo实例 def get_temporary_photo_url(photo): temp_link = TemporaryPhotoLink.generate_for_photo(photo) # 拼接得到完整访问链接 return reverse('temp_photo_access', args=[str(temp_link.access_token)])
3. 实现访问验证视图
新增视图函数处理临时链接的访问校验,有效则返回图片资源,无效返回404:
from django.http import HttpResponse, Http404 from django.shortcuts import get_object_or_404 from django.conf import settings import os def temp_photo_access(request, token): temp_link = get_object_or_404(TemporaryPhotoLink, access_token=token) # 校验链接有效性 if not temp_link.is_valid(): raise Http404("链接已过期或失效") # 不需要单次访问失效的话可以删掉下面两行 temp_link.is_used = True temp_link.save() # 生产环境建议用Nginx X-Accel-Redirect/Apache X-Sendfile处理文件响应,降低Django压力 photo_path = os.path.join(settings.MEDIA_ROOT, temp_link.photo.photo.name) with open(photo_path, 'rb') as f: response = HttpResponse(f.read(), content_type="image/jpeg") response['Content-Disposition'] = 'inline; filename=' + os.path.basename(photo_path) return response
4. 优化建议
- 定期清理已经过期的
TemporaryPhotoLink记录,可以写Django管理命令结合crontab定时执行,避免无效数据占用数据库空间 - 如果你使用云存储(阿里云OSS、腾讯云COS、AWS S3等),可以直接使用云存储自带的签名URL功能,不需要自行维护临时链接表,直接指定过期时间即可,性能更高、维护成本更低
内容的提问来源于stack exchange,提问作者azarjaved
相关产品推荐
相关产品推荐

