Django:如何用原生JS的Fetch替代Ajax实现按钮点击不刷新页面?
解决方案:无刷新提交表单并更新内容
步骤1:重构Django视图与表单,统一管理选项
首先修改views.py,拆分出专门处理AJAX请求的视图,同时从forms.py的SimpleCombobox类中读取选项,避免硬编码,方便后续扩展:
修改后的views.py
from django.http import JsonResponse from django.shortcuts import render from django.contrib.auth.decorators import login_required from .forms import SimpleCombobox @login_required def home(request): # 从表单类中获取颜色选项,统一管理 color_choices = [choice[0] for choice in SimpleCombobox.COLOR_CHOICES] context = {'color_choices': color_choices} return render(request, 'app1/home.html', context) @login_required def get_color_message(request): if request.method == "POST" and request.headers.get('X-Requested-With') == 'XMLHttpRequest': picked = request.POST.get('color') message = '' if picked == 'Red': message = "<<< You chose red" elif picked == 'Blue': message = "<<< You chose blue" elif picked == 'Black': message = "<<< You chose black" else: message = "<<< Oh no, you chose orange" return JsonResponse({'message': message}) return JsonResponse({'error': 'Invalid request'}, status=400)
沿用并扩展forms.py(统一管理选项)
已有的SimpleCombobox类可直接使用,后续新增下拉框选项时,只需在此文件添加新表单类即可,无需修改JS或视图核心逻辑:
from django import forms class SimpleCombobox(forms.Form): Col1 = 'Red' Col2 = 'Blue' Col3 = 'Black' Col4 = 'Orange' COLOR_CHOICES = ( (Col1, u"Red"), (Col2, u"Blue"), (Col3, u"Black"), (Col4, u"Orange"), ) cities = forms.ChoiceField(choices=COLOR_CHOICES) # 后续新增下拉框可在此添加新表单类 # class AnotherCombobox(forms.Form): # ... class SimpleTextbox(forms.Form): coverletter = forms.CharField(required=False, widget=forms.Textarea( attrs={'rows': 4, 'cols': 40})) class LoginForm(forms.Form): username = forms.CharField(max_length=65) password = forms.CharField(max_length=65, widget=forms.PasswordInput)
步骤2:配置URL路由
在项目或应用的urls.py中添加AJAX请求路由:
from django.urls import path from . import views urlpatterns = [ path('home/', views.home, name='home'), path('get-color-message/', views.get_color_message, name='get-color-message'), # 其他路由... ]
步骤3:修改前端HTML与添加原生JS
修改home.html,阻止表单默认刷新行为,使用Fetch API发送异步请求并更新textarea内容:
修改后的home.html
{% extends 'app1/base.html' %} {% load static %} {% block content %} <div class="container p-5"> <div class="row mx-auto"> <div class="col-6"> <form class="form-group" id="color-form"> {% csrf_token %} <select name="color" class="form-select" id="color-select"> {% for i in color_choices %} <option value="{{i}}">{{i}}</option> {% endfor %} </select> <textarea class="form-control" name="msg" id="message-area" cols="30" rows="10"></textarea> <button class="btn btn-primary mt-3" type="button" id="submit-btn">Submit</button> </form> </div> </div> </div> <script> // 获取DOM元素 const submitBtn = document.getElementById('submit-btn'); const messageArea = document.getElementById('message-area'); const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value; submitBtn.addEventListener('click', async () => { const selectedColor = document.getElementById('color-select').value; try { const response = await fetch('{% url "get-color-message" %}', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-CSRFToken': csrfToken, 'X-Requested-With': 'XMLHttpRequest' // 标识AJAX请求 }, body: `color=${encodeURIComponent(selectedColor)}` }); if (!response.ok) throw new Error('请求失败'); const data = await response.json(); messageArea.value = data.message; } catch (error) { messageArea.value = '获取内容失败,请重试'; console.error(error); } }); </script> {% endblock content%}
核心优势说明
- 无刷新实现:将按钮类型改为
button避免默认表单提交,通过Fetch API发送异步请求,直接更新textarea内容,完全避免页面刷新。 - 集中管理配置:所有下拉选项统一在
forms.py中维护,后续新增下拉框时只需扩展表单类,无需拆分或修改大量JS代码。 - 合法请求保护:请求中携带Django的CSRF令牌,符合框架安全要求。
- 扩展性强:后续新增多下拉框时,只需在视图中添加对应逻辑,前端JS可复用核心Fetch请求逻辑,仅需调整提交参数即可。
内容的提问来源于stack exchange,提问作者Zollikofen4
相关产品推荐
相关产品推荐

