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

Django问题:GET请求后页面重载导致Bootstrap折叠按钮状态重置

解决Bootstrap折叠按钮与表单提交页面重载的冲突问题

问题分析

当前代码里,按钮同时承担了表单提交(type="submit")和Bootstrap折叠触发器的角色,点击时会先触发折叠的JS逻辑,随即提交表单导致页面重载——前端维护的折叠状态会被重置,同时后端返回的grades数据会被所有科目折叠框复用,无法实现每个科目独立展示自身成绩的需求。

解决方案

方案一:AJAX异步加载成绩(推荐)

通过异步请求获取成绩,无需页面重载,彻底避免折叠状态丢失,还能实现每个科目独立加载数据。

1. 新增后端API接口

在views.py中添加处理AJAX请求的视图:

from django.http import JsonResponse

def get_subject_grades(request):
    if request.user.is_authenticated and request.method == 'GET':
        subject = request.GET.get('subject', '')
        if subject:
            # 假设get_grades返回可序列化的成绩列表,若为对象需转换为字符串
            grades = Test.get_grades(student=request.user.id, subject=subject, self=Test)
            return JsonResponse({'grades': [str(g) for g in grades]})
        return JsonResponse({'grades': []})
    return JsonResponse({'error': '未登录'}, status=401)

在urls.py中配置路由:

path('get-grades/', views.get_subject_grades, name='get_subject_grades'),

2. 修改前端模板,移除表单改用AJAX

调整noten.html,去掉表单,将按钮改为普通按钮,添加JS逻辑处理点击事件:

{% if subject_list %}
    <ul>
        {% for subject in subject_list %}
            <p>
                <button class="btn btn-primary" type="button" data-bs-toggle="collapse" 
                        data-bs-target="#{{ subject }}" aria-expanded="false" 
                        aria-controls="{{ subject }}" data-subject="{{ subject }}">
                    {{ subject }}
                </button>
            </p>
            <div class="collapse" id="{{ subject }}">
                <div class="card card-body" id="grades-container-{{ subject }}">
                    <p>加载中...</p>
                </div>
            </div>
        {% endfor %}
    </ul>

    <script>
        // 绑定所有科目按钮的点击事件
        document.querySelectorAll('.btn-primary[data-subject]').forEach(button => {
            button.addEventListener('click', function() {
                const subject = this.dataset.subject;
                const container = document.getElementById(`grades-container-${subject}`);
                
                // 避免重复加载
                if (container.dataset.loaded === 'true') return;

                // 发送异步请求
                fetch(`{% url 'get_subject_grades' %}?subject=${encodeURIComponent(subject)}`)
                    .then(res => res.json())
                    .then(data => {
                        if (data.error) {
                            container.innerHTML = '<p>获取成绩失败,请重新登录</p>';
                            return;
                        }
                        if (data.grades.length > 0) {
                            let html = '<ul>';
                            data.grades.forEach(grade => html += `<li>${grade}</li>`);
                            html += '</ul>';
                            container.innerHTML = html;
                        } else {
                            container.innerHTML = '<p>Du hast keine Noten in diesem Fach!</p>';
                        }
                        container.dataset.loaded = 'true';
                    })
                    .catch(err => {
                        container.innerHTML = '<p>加载成绩时出错</p>';
                        console.error(err);
                    });
            });
        });
    </script>
{% endif %}

方案二:表单提交后恢复折叠状态

如果不想用AJAX,可通过URL参数标记当前展开的科目,后端渲染时给对应折叠框添加show类,重载后保持展开状态。

1. 修改后端视图,传递当前选中科目

更新views.py的noten函数:

def noten(request):
    if request.user.is_authenticated:
        object_list = Subject.objects.order_by('name')
        subject_list = [sub.name for sub in object_list]
        current_subject = request.GET.get('subject', '')
        grades = []
        if current_subject:
            grades = Test.get_grades(student=request.user.id, subject=current_subject, self=Test)
        
        return render(request, 'noten.html', {
            'subject_list': subject_list,
            'grades': grades,
            'current_subject': current_subject
        })
    else:
        return redirect('loginForm:login')

2. 调整前端模板,根据参数设置折叠状态

修改noten.html:

{% if subject_list %}
    <form name="subject-list" method="GET">
        <ul>
            {% for subject in subject_list %}
                <p>
                    <button class="btn btn-primary" type="submit" data-bs-toggle="collapse" 
                            data-bs-target="#{{ subject }}" aria-expanded="{{ subject == current_subject|lower }}" 
                            aria-controls="{{ subject }}" value="{{ subject }}" name="subject">
                        {{ subject }}
                    </button>
                </p>
                <div class="collapse {% if subject == current_subject %}show{% endif %}" id="{{ subject }}">
                    <div class="card card-body">
                        {% if subject == current_subject %}
                            {% if grades %}
                                {% for grade in grades %}
                                    <li>{{ grade }}</li>
                                {% endfor %}
                            {% else %}
                                <p>Du hast keine Noten in diesem Fach!</p>
                            {% endif %}
                        {% else %}
                            <p>点击按钮查看成绩</p>
                        {% endif %}
                    </div>
                </div>
            {% endfor %}
        </ul>
    </form>
{% endif %}

注意:此方案仍会触发页面重载,且同一时间只能显示一个科目的成绩。

额外优化建议

  • 方案一中可添加防抖逻辑,防止用户短时间内重复点击
  • 方案二中给按钮添加autocomplete="off",避免浏览器自动填充干扰
  • 检查Test.get_grades方法的调用方式,self=Test写法不符合常规类方法调用,建议改为Test.get_grades(student=request.user.id, subject=subject)(若get_grades是类方法)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 01:50:48