如何在Django中使用Subquery代码显示Amazon S3存储的图片?
问题原因
你当前通过Subquery直接提取photo字段值时,得到的是文件在S3中的相对路径字符串,而非Django的ImageFieldFile实例——只有这类实例才会自动拼接S3域名,生成可直接访问的完整URL。因此直接使用路径字符串无法加载图片,也不存在.photo或.url属性。
解决方案
方案一:数据库层面拼接完整URL(推荐)
通过数据库函数直接拼接MEDIA_URL和文件路径,在查询阶段就生成完整的S3访问地址:
- 导入必要依赖
from django.db.models import Value, Concat, Subquery, OuterRef from django.conf import settings from django.http import Http404
- 修改查询代码
try: user = MyUser.objects.get(pk=5) except MyUser.DoesNotExist: raise Http404() # 筛选优先级为1的ItemPhoto,仅取photo字段 photo_subqs = ItemPhoto.objects.filter( item=OuterRef('item'), priority=1 ).values('photo') queryset = Order.objects.prefetch_related( Prefetch( 'orderdetail_orderid', queryset=OrderDetail.objects.select_related('order', 'item').annotate( # 拼接MEDIA_URL与photo路径,生成完整访问URL item_photo_url=Subquery( Concat( Value(settings.MEDIA_URL), photo_subqs.values('photo'), output_field=models.CharField() ) ) ), to_attr='oor', ), ).filter(user=user).order_by('-created_at')
- 模板中直接使用
{% for order in orders %} {% for item in order.oor %} <img src="{{ item.item_photo_url }}"> {% endfor %} {% endfor %}
方案二:模板手动拼接MEDIA_URL
若不想修改查询逻辑,可在模板中手动拼接媒体域名前缀,前提是确保MEDIA_URL能在模板中访问:
- 确认模板上下文配置
在settings.py的模板配置中,确保包含媒体上下文处理器:
TEMPLATES = [ { # 其他配置项 'OPTIONS': { 'context_processors': [ # 其他处理器 'django.template.context_processors.media', ], }, }, ]
- 修改模板代码
{% for order in orders %} {% for item in order.oor %} <img src="{{ MEDIA_URL }}{{ item.item_photos }}"> {% endfor %} {% endfor %}
方案三:预取ItemPhoto实例(符合Django ORM习惯)
放弃Subquery,改用嵌套Prefetch直接获取ItemPhoto实例,直接调用实例的.photo.url属性:
- 修改查询代码
user = get_object_or_404(MyUser, pk=5) # 预取每个Item下优先级为1的照片 photo_prefetch = Prefetch( 'item__item_photo', queryset=ItemPhoto.objects.filter(priority=1), to_attr='priority_photos' ) queryset = Order.objects.prefetch_related( Prefetch( 'orderdetail_orderid', queryset=OrderDetail.objects.select_related('order', 'item').prefetch_related(photo_prefetch), to_attr='oor', ), ).filter(user=user).order_by('-created_at')
- 模板中遍历使用
{% for order in orders %} {% for item in order.oor %} {% for photo in item.item.priority_photos %} <img src="{{ photo.photo.url }}"> {% endfor %} {% endfor %} {% endfor %}
内容的提问来源于stack exchange,提问作者K-Yuuma
相关产品推荐
相关产品推荐

