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

Django HTML模板嵌套循环异常:无法按用户预订状态显示对应按钮

问题:已预订会话显示quit按钮,未预订显示book按钮无法实现

需求:登录用户已预订的会话显示'quit'按钮,未预订的会话显示'book'按钮,当前无法实现该功能。

模型代码

class Member(models.Model):
    gym = models.ForeignKey(Gym, on_delete=models.CASCADE, blank=True, null=True, related_name="gym_membership")
    member = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True, related_name="member_of_gym")

    def __str__(self):
        return f'{self.member.username}'

class Session(models.Model):
    program = models.ForeignKey(Program, on_delete=models.CASCADE, blank=True, null=True, related_name="session_program")
    focus = models.ForeignKey(Focus, on_delete=models.CASCADE, blank=True, null=True, related_name="session_focus")
    location = models.ForeignKey(Location, on_delete=models.CASCADE, blank=True, null=True, related_name="session_location")
    booking_counter = models.IntegerField(default=0)
    start_datetime: datetime = models.DateTimeField()
    duration = models.DurationField()
    day = models.CharField(max_length=12, blank=True, null=True)
    week_number = models.IntegerField(blank=True, null=True)

    def __str__(self):
        return f'{self.program}, {self.day} - Week {self.week_number}'


class Booking(models.Model):
    member = models.ForeignKey(Member, on_delete=models.CASCADE, blank=True, null=True, related_name="member_booking")
    session = models.ForeignKey(Session, on_delete=models.CASCADE, blank=True, null=True, related_name="booking_session")
    booking = models.BooleanField()
    date_booked = models.DateTimeField()
    date_cancelled = models.DateTimeField(blank=True, null=True)
    attendance_verified = models.BooleanField(blank=True, null=True)

    def __str__(self):
        return f'{self.member.member.username} booked {self.session}'

视图代码

def index(request):
    # store the user information in a variable
    user = request.user
    # get the membership object for that user
    member = Member.objects.get(member=user.id)
    context = {
        "sessions": Session.objects.all(),
        "bookings": Booking.objects.filter(member=member)
    }
    return render(request, "booking/index.html", context)

模板代码(index.html)

{% extends "booking/layout.html" %}

{% block body %}

{% if user.is_authenticated %}

    <h2>INTERFACE</h2>

    <p>WEEK X < ></p>
    <br>

    <class class="card">
        <div class="card-header">
          BOOKINGS
        </div>
        <ul class="list-group list-group-flush">
            {% for session in sessions %}
                <li class="list-group-item">{{ session.day }}: <a href="{% url 'session' session.id %}">{{ session.program }} </a>
                    <form class="nav-item ms-auto float-end" action="{% url 'book' session.id %}" method="post">
                        {% csrf_token %}
{#                        {% for booking in bookings %}#}
                        {% for booking in session.booking_session %}
                            {% if booking.session == session %}
                                <button type="submit" class="btn btn-outline-light ms-auto btn-sm">quit</button>
                            {% else %}
                                <button type="submit" class="btn btn-outline-light ms-auto btn-sm">book</button>
                            {% endif %}
                        {% endfor %}
                    </form>
                </li>
            {% endfor %}
        </ul>
    </class>

{% endif %}

{% endblock %}

原实现问题分析

  • 模板遍历session.booking_session会获取该会话的所有预订记录(包含其他用户的),导致按钮判断错误或重复显示
  • 未过滤Booking模型中booking=True的有效预订状态
  • 嵌套循环逻辑冗余,无法精准匹配当前用户的预订状态

修改方案

1. 优化视图代码

提前获取当前用户已预订的会话ID集合,减少模板中的数据库查询:

def index(request):
    user = request.user
    # 直接传入user对象而非id,符合ORM规范
    member = Member.objects.get(member=user)
    # 获取当前用户的有效预订会话ID集合(过滤booking=True的记录)
    booked_session_ids = set(
        Booking.objects.filter(member=member, booking=True)
        .values_list('session__id', flat=True)
    )
    context = {
        "sessions": Session.objects.all(),
        "booked_session_ids": booked_session_ids
    }
    return render(request, "booking/index.html", context)

2. 修改模板代码

去掉嵌套循环,直接通过会话ID判断预订状态,同时修正模板标签错误:

{% extends "booking/layout.html" %}

{% block body %}

{% if user.is_authenticated %}

    <h2>INTERFACE</h2>

    <p>WEEK X < ></p>
    <br>

    <div class="card">
        <div class="card-header">
          BOOKINGS
        </div>
        <ul class="list-group list-group-flush">
            {% for session in sessions %}
                <li class="list-group-item">{{ session.day }}: <a href="{% url 'session' session.id %}">{{ session.program }} </a>
                    <form class="nav-item ms-auto float-end" action="{% url 'book' session.id %}" method="post">
                        {% csrf_token %}
                        {% if session.id in booked_session_ids %}
                            <button type="submit" class="btn btn-outline-light ms-auto btn-sm">quit</button>
                        {% else %}
                            <button type="submit" class="btn btn-outline-light ms-auto btn-sm">book</button>
                        {% endif %}
                    </form>
                </li>
            {% endfor %}
        </ul>
    </div>

{% endif %}

{% endblock %}

注:原模板中<class class="card">为错误写法,已修正为<div class="card">。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 02:25:13