Django关联模型查询:如何在模板展示订单及关联预订
嘿,针对你的Django订单与预订嵌套展示需求,我来给你梳理下最优的实现方案——核心是解决N+1查询问题,同时简化模板逻辑:
你当前循环每个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
相关产品推荐
相关产品推荐

