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

Django关联模型查询:如何在模板展示订单及关联预订

嘿,针对你的Django订单与预订嵌套展示需求,我来给你梳理下最优的实现方案——核心是解决N+1查询问题,同时简化模板逻辑:

1. 优化查询:用prefetch_related避免重复查询

你当前循环每个Order去查对应的Booking,会触发N+1次数据库查询(1次查所有Order,N次查每个Order的Booking),性能很差。Django提供了prefetch_related来批量预取反向关联的对象,完美解决这个问题。

因为你的Booking模型通过ForeignKey关联到Order,所以Order对象会自动拥有一个反向关联属性booking_set(默认命名规则是小写模型名_set)。我们可以在查询Order时,一次性预取所有关联的Booking:

修改视图中的Order查询代码:

def shopDashboardPastBookings(request):
    # 注意:请确保shopID是当前请求可获取的合法变量(比如从session、URL参数等获取)
    orders = Order.objects.filter(shop_id=shopID)\
                          .exclude(order_date__gte=(datetime.now() - timedelta(days=1)))\
                          .prefetch_related('booking_set')  # 关键:一次性预取所有关联的Booking
    
    paginator = Paginator(orders, 10)
    page = request.GET.get('page')
    paged_orders = paginator.get_page(page)
    
    # 不需要再维护bookings字典,直接传分页后的orders即可
    context = {
        'orders': paged_orders,
    }
    return render(request, 'dashboard-pastbookings.html', context)
2. 模板中实现嵌套展示

现在每个order对象已经自带了booking_set属性,直接在模板里嵌套循环就能实现需求:

{% for order in orders %}
    <div class="order-card">
        <h3>订单ID: {{ order.order_id }}</h3>
        <p>下单日期: {{ order.order_date }}</p>
        <div class="bookings-section">
            <h4>关联预订:</h4>
            <ul>
                {% for booking in order.booking_set.all %}
                    <li>服务名称: {{ booking.service.name }}</li>  <!-- 假设Service模型有name字段 -->
                {% empty %}
                    <li>该订单无关联预订</li>
                {% endfor %}
            </ul>
        </div>
    </div>
{% empty %}
    <p>暂无历史订单记录</p>
{% endfor %}

<!-- 分页导航(可选) -->
<div class="pagination">
    {% if orders.has_previous %}
        <a href="?page={{ orders.previous_page_number }}">上一页</a>
    {% endif %}
    <span>第 {{ orders.number }} 页 / 共 {{ orders.paginator.num_pages }} 页</span>
    {% if orders.has_next %}
        <a href="?page={{ orders.next_page_number }}">下一页</a>
    {% endif %}
</div>
额外优化:自定义反向关联名称(可选)

如果你觉得booking_set这个名字不够直观,可以在Booking模型的ForeignKey里指定related_name,让代码可读性更强:

class Booking(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE, blank=True, null=True, related_name='bookings')
    service = models.ForeignKey(Service, on_delete=models.CASCADE, blank=True, null=True)

修改后,查询时可以用prefetch_related('bookings'),模板里直接写order.bookings.all()即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:32:51