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

Django多表关联查询:如何获取商品关联的所有图片

Django电商网站:获取商品关联图片的实现方案

你的现有模型与查询代码

模型定义

class ProductDetail(models.Model):        
    product= models.ForeignKey(Product, on_delete=models.CASCADE)
    category= models.ForeignKey(ProductCategory, on_delete=models.CASCADE)
    sub_category= models.ForeignKey(ProductSubCategory, on_delete=models.CASCADE)    
    created_at= models.DateTimeField(auto_now_add=datetime)
    updated_at= models.DateTimeField(blank=True, null=True)
    deleted_at= models.DateTimeField(blank=True, null=True)

class ProductImage(models.Model):      
    img_type_choices = (
        ('Primary', "Primary"),
        ('Secondary', "Secondary"),
    )  
    product= models.ForeignKey(Product, on_delete=models.CASCADE)
    img= models.FileField(upload_to="shop/product_images", default="")
    type= models.CharField(max_length=12, choices=img_type_choices, default='Primary')
    created_at= models.DateTimeField(auto_now_add=datetime)
    updated_at= models.DateTimeField(blank=True, null=True)
    deleted_at= models.DateTimeField(blank=True, null=True)    

当前查询代码

from shop.models import ProductSubCategory, ProductImage, ProductCategory, Product, ProductDetail

def index(request):
   products = ProductDetail.objects.values('product__name','product__product_id', 'product__price', 'product__desc', 'category__name', 'sub_category__name', 'category')

实现方案

方案1:预取关联图片(推荐,适合模板渲染场景)

利用select_related(正向关联查询)和prefetch_related(反向关联预取),一次性拉取所有需要的数据,避免N+1查询问题:

from django.db.models import Prefetch
from shop.models import ProductDetail

def index(request):
    # 预取关联的Product、分类信息,同时预取每个商品的所有图片
    products = ProductDetail.objects.select_related(
        'product', 'category', 'sub_category'
    ).prefetch_related(
        Prefetch('product__productimage_set', queryset=ProductImage.objects.all())
    )
    return render(request, 'your_template.html', {'products': products})

在模板中遍历图片:

{% for item in products %}
    <div class="product-card">
        <h4>{{ item.product.name }}</h4>
        <p>价格:¥{{ item.product.price }}</p>
        <p>分类:{{ item.category.name }} > {{ item.sub_category.name }}</p>
        <!-- 展示所有关联图片 -->
        <div class="product-images">
            {% for img in item.product.productimage_set.all %}
                <img src="{{ img.img.url }}" alt="{{ item.product.name }} 图片">
            {% endfor %}
        </div>
    </div>
{% endfor %}

方案2:用聚合将图片URL存入字典(适合API返回场景)

如果需要保持values()的字典格式,可以用ArrayAgg聚合所有图片URL到一个字段:

from django.db.models import ArrayAgg, F
from shop.models import ProductDetail

def index(request):
    products = ProductDetail.objects.values(
        'product__name', 'product__product_id', 'product__price', 'product__desc',
        'category__name', 'sub_category__name', 'category'
    ).annotate(
        # 聚合当前商品的所有图片URL
        product_images=ArrayAgg(F('product__productimage__img__url'))
    )
    # 此时每个products元素是包含product_images列表的字典
    return render(request, 'your_template.html', {'products': products})

模板中使用:

{% for item in products %}
    <div class="product-card">
        <h4>{{ item.product__name }}</h4>
        <p>价格:¥{{ item.product__price }}</p>
        <div class="product-images">
            {% for img_url in item.product_images %}
                <img src="{{ img_url }}" alt="{{ item.product__name }} 图片">
            {% endfor %}
        </div>
    </div>
{% endfor %}

注意事项

  • 确保项目已正确配置MEDIA_URL和MEDIA_ROOT,否则img.url无法返回正确的图片访问路径。
  • 若只需要主图,可以在Prefetch的queryset中添加过滤:ProductImage.objects.filter(type='Primary')

内容的提问来源于stack exchange,提问作者Vishnu Fauzdar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 09:08:24