英文:
Django: How to prevent a page from reloading when I click button with Ajax/Javascript? (not jQuery)
问题
在home.html
页面(index.html > login.html > home.html)中,我有以下内容:
combobox
(独立的,与数据库无关,而是与列表相关);textarea
;button
。
当我点击按钮时,它会在文本区域中打印一些文本(使用views.py
中找到的条件)。非常简单。
问题: 问题在于当我点击按钮时,页面会重新加载,然后才会在文本区域中打印内容。在没有使用jQuery的情况下,如何使用Ajax/Javascript阻止页面在点击按钮时重新加载?谢谢大家!
重要提示: 请记住,我将不得不添加许多组合框,因此我希望尽可能好地管理它们。是否可能在py文件中尽可能多地管理代码,而不是将其分割成js文件或js标签?
P.S: 我在stackoverflow上搜索了很多问题或各种教程,但都无法解决。显然,尽管这些问题相似,但每个解决方案都是不同的情况,存在不同的问题和解决方案。
我希望有人能帮助我。谢谢大家!
代码
home.html(index > login > home)
index.html是127.0.0.1:8000/
。只有成功登录后,Home.html才会打开。当我查看表单时的地址是127.0.0.1:8000/home
,当我点击提交时,我仍然得到127.0.0.1:8000/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 action="" method="POST" novalidate class="form-group">
{% csrf_token %}
<select name="color" class="form-select">
{% for i in color_choices %}
<option value="{{i}}">{{i}}</option>
{% endfor %}
</select>
<textarea class="form-control" name="msg" cols="30" rows="10">{{message}}</textarea>
<button class="btn btn-primary mt-3" type="submit">Submit</button>
</form>
</div>
</div>
</div>
{% endblock content %}
views.py
@login_required
def home(request):
color_choices = ("Red","Blue","Black","Orange")
message = ''
if request.method == "POST":
picked = request.POST.get('color')
if picked == 'Red':
message = "<<< You chose red"
print(message)
elif picked == 'Blue':
message = "<<< You chose blue"
elif picked == 'Black':
message = "<<< You chose black"
else:
message = "<<< Oh no, you chose orange"
context = {'message':message,'color_choices':color_choices}
return render(request, 'app1/home.html', context)
forms.py
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 SimpleTextbox(forms.Form):
coverletter = forms.CharField(required=False,
widget=forms.Textarea(
# rows and colums of the 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)
英文:
Premise: A question that can be useful to many. Fetch instead of Ajax. Today Ajax is often replaced by the newer Fetch in Javascript, which provides a better alternative. If you're looking for a way to avoid page reloading, I recommend using Fetch in pure Javascript. Ajax is still used and still great, but Fetch offers a more modern solution.
In the home.html page
(index.html > login.html > home.html) i have a:
combobox
(independent, not connected to the database but to a list);textarea
;button
;
When i click the button, it prints some text in the textarea (using a condition found in views.py
). Very simple.
Problem: The problem is that when i click the button, the page reloads and then prints in the textarea. How can I prevent the page from reloading, with Ajax/Javascript, when i click the button (without using jQuery)? Thank you all!
Important: bearing in mind that I will have to add many comboboxes, so I would like to manage them as best as possible. Is it possible to manage the code as much as possible in the py files and not split it too much in the js file or js tag?
P.S: I searched many questions on stackoverflow or various tutorials, but I couldn't solve. Apparently, even though these are similar questions, each solution is a different case with different problems and solutions.
I hope someone can help me. Thank you all!
CODE
home.html (index > login > home)
index.html is 127.0.0.1:8000/
. Home.html will only open after successful login. The address of when I view the forms is 127.0.0.1:8000/home
and when I click Submit I still get 127.0.0.1:8000/home (rightfully so). Obviously I wrote the html in a reduced and shorter way:
{% extends 'app1/base.html' %}
{% load static %}
{% block content %}
<div class="container p-5">
<div class="row mx-auto">
<div class="col-6">
<form action="" method="POST" novalidate class="form-group">
{% csrf_token %}
<select name="color" class="form-select" >
{% for i in color_choices %}
<option value="{{i}}">{{i}}</option>
{% endfor %}
</select>
<textarea class="form-control" name="msg" cols="30" rows="10">{{message}}</textarea>
<button class="btn btn-primary mt-3" type="submit">Submit</button>
</form>
</div>
</div>
</div>
{% endblock content%}
views.py
@login_required
def home(request):
color_choices = ("Red","Blue","Black","Orange")
message =''
if request.method =="POST":
picked = request.POST.get('color')
if picked == 'Red':
message = "<<< You chose red"
print(message)
elif picked == 'Blue':
message = "<<< You chose blue"
elif picked == 'Black':
message = "<<< You chose black"
else:
message = "<<< Oh no, you chose orange"
context = {'message':message,'color_choices':color_choices}
return render(request, 'app1/home.html', context)
forms.py
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 SimpleTextbox(forms.Form):
coverletter = forms.CharField(required=False,
widget=forms.Textarea(
# rows and colums of the textarea
attrs={'rows': 4, 'cols': 40}))
#LOGIN
class LoginForm(forms.Form):
username = forms.CharField(max_length=65)
password = forms.CharField(max_length=65, widget=forms.PasswordInput)
答案1
得分: 1
基本上,通过使用.preventDefault
来阻止默认的点击处理。然后,您可以使用Fetch API
发送post
请求,并且需要从cookies中检索csrftoken
并将其设置在请求标头
上。以下是一个示例:
{% block content %}
<div class="container p-5">
<div class="row mx-auto">
<div class="col-6">
<form action="" method="POST" novalidate class="form-group">
{% csrf_token %}
<select id="select-color" name="color" class="form-select" >
{% for i in color_choices %}
<option value="{{i}}">{{i}}</option>
{% endfor %}
</select>
<textarea id="text-message" class="form-control" name="msg" cols="30" rows="10">{{message}}</textarea>
<button class="btn btn-primary mt-3" type="submit" id="button-submit">Submit</button>
</form>
</div>
</div>
</div>
<script>
function getCookie(name) {
// ...
}
async function postData(url = "", data = {}) {
const csrftoken = getCookie('csrftoken');
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": csrftoken,
},
body: JSON.stringify(data),
});
return response.json();
}
document.getElementById("button-submit").addEventListener("click", (event) => {
event.preventDefault();
const selected_color = document.getElementById("select-color").value;
postData(url="{% url 'fetch-message' %}", {color: selected_color})
.then((response) => {
document.getElementById("text-message").innerHTML = response.message
});
});
</script>
{% endblock content%}
您可以在一个视图中完成,但最好将它们分开:
@login_required
def home(request):
color_choices = ("Red","Blue","Black","Orange")
context = {'color_choices':color_choices}
return render(request, 'app1/home.html', context)
def fetch_message(request):
data = json.loads(request.body)
picked = data['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})
urls.py
urlpatterns = [
path('', home, name='home'),
path('fetch/message/', fetch_message, name='fetch-message'),
]
重要的是name='fetch-message'
,这样我们可以在模板中使用{% url 'fetch-message' %}
来反向解析URL。
英文:
Basically by blocking the default click handling by using .preventDefault
. Then you can send a post
request using the Fetch API
and for that you will need to retrieve csrftoken
from cookies and set it on the request headers
. Here is an example:
{% block content %}
<div class="container p-5">
<div class="row mx-auto">
<div class="col-6">
<form action="" method="POST" novalidate class="form-group">
{% csrf_token %}
<select id="select-color" name="color" class="form-select" >
{% for i in color_choices %}
<option value="{{i}}">{{i}}</option>
{% endfor %}
</select>
<textarea id="text-message" class="form-control" name="msg" cols="30" rows="10">{{message}}</textarea>
<button class="btn btn-primary mt-3" type="submit" id="button-submit">Submit</button>
</form>
</div>
</div>
</div>
<script>
function getCookie(name) {
...
}
async function postData(url = "", data = {}) {
const csrftoken = getCookie('csrftoken');
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": csrftoken,
},
body: JSON.stringify(data),
});
return response.json();
}
document.getElementById("button-submit").addEventListener("click", (event) => {
event.preventDefault();
const selected_color = document.getElementById("select-color").value;
postData(url="{% url 'fetch-message' %}", {color: selected_color})
.then((response) => {
document.getElementById("text-message").innerHTML = response.message
});
});
</script>
{% endblock content%}
You could do it in just one view, but it is good practice to keep them apart:
@login_required
def home(request):
color_choices = ("Red","Blue","Black","Orange")
context = {'color_choices':color_choices}
return render(request, 'app1/home.html', context)
def fetch_message(request):
data = json.loads(request.body)
picked = data['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})
urls.py
urlpatterns = [
path('', home, name='home'),
path('fetch/message/', fetch_message, name='fetch-message'),
]
What is important is name='fetch-message'
, so that we can reverse resolve the URL on the template
with {% url 'fetch-message' %}
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论