AJAX
AJAX ๊ฐ์
โ Asynchronous Javascript And XML (๋น๋๊ธฐ ํต์ ์น ๊ฐ๋ฐ ๊ธฐ์ )
โ ๋น๋๊ธฐ ํต์ ์ ์ด์ฉํด ํ๋ฉด ์ ์ฒด๋ฅผ ์๋ก๊ณ ์นจ ํ์ง ์๊ณ ๋ ์๋ฒ ์์ฒญ์ ๋ณด๋ด๊ณ , ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ํ๋ฉด์ ์ผ๋ถ๋ถ๋ง ์
๋ฐ์ดํธ ํ๋ ๊ธฐ๋ฅ
AJAX์ ํน์ง
- ํ์ด์ง ์๋ก ๊ณ ์นจ ์์ด ์๋ฒ์ ์์ฒญ
- ์๋ฒ๋ก๋ถํฐ ์๋ต(๋ฐ์ดํฐ)๋ฅผ ๋ฐ์ ์์ ์ ์ํ
AJAX๋ฅผ ์ด์ฉํด Django follow ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ
์ฌ์ ์ค๋น
- ํ ํ๋ฆฟ์ script ์ฝ๋ ์์ฑ์ ์ํ block tag ์์ญ ์์ฑ
<!-- base.html -->
<body>
...
{% block script %}
{% endblock script %}
</body>
- axios CDN ์์ฑ
<!-- accounts/profile.html -->
{% block script %}
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
</script>
{% endblock script %}
- id ์์ฑ ์ง์ ๋ฐ ์ ํ, ๋ถํ์ํ action๊ณผ method ์ญ์ (์์ฒญ์ axios๋ก ๋์ฒด๋๋ค.)
<!-- accounts/profile.html -->
<form id="follow-form">...</form>
<!-- accounts/profile.html -->
<script>
const form = document.querySelector("#follow-form");
</script>
- form ์์์ ์ด๋ฒคํธ ํธ๋ค๋ฌ ์์ฑ ๋ฐ submit ์ด๋ฒคํธ ์ทจ์
<!-- accounts/profile.html -->
<script>
const form = document.querySelector("#follow-form");
form.addEventListener("submit", function (event) {
event.preventDefault();
});
</script>
- axios ์์ฒญ ์ค๋น
<!-- accounts/profile.html -->
<script>
const form = document.querySelector('#follow-form')
form.addEventListener('submit', function (event) {
event.preventDefault()
axios({
method: 'post',
url: `/accounts/${???}/follow/`,
})
})
</script>
1. url์ ์์ฑํ user pk ์์ฑ
- url์ ์์ฑํ user pk ๊ฐ์ ธ์ค๊ธฐ (HTML > JavaScript)
<!-- accounts/profile.html -->
<form id="follow-form" data-user-id="{{ person.pk }}">...</form>
<!-- accounts/profile.html -->
<script>
const form = document.querySelector("#follow-form");
form.addEventListener("submit", function (event) {
event.preventDefault();
const userId = event.target.dataset.userId;
});
</script>
- url ์์ฑ ๋ง์น๊ธฐ
<!-- accounts/profile.html -->
<script>
const form = document.querySelector("#follow-form");
form.addEventListener("submit", function (event) {
event.preventDefault();
axios({
method: "post",
url: `/accounts/${userId}/follow/`,
});
});
</script>
data-* attributes
โ ์ฌ์ฉ์ ์ง์ ๋ฐ์ดํฐ ํน์ฑ์ ๋ง๋ค์ด ์์์ ๋ฐ์ดํฐ๋ฅผ HTML๊ณผ DOM ์ฌ์ด์์ ๊ตํํ ์ ์๋ ๋ฐฉ๋ฒ
โ ์ฌ์ฉ ์์
<div data-my-id="my-data"></div>
<script>
const myId = event.targe.dataset.myId;
</script>
โ data-test-value
๋ผ๋ ์ด๋ฆ์ ํน์ฑ์ ์ง์ ํ๋ค๋ฉด JavaScript์์๋ element.dataset.testValue
๋ก ์ ๊ทผํ ์ ์๋ค.
โ ์์ฑ๋ช
์์ฑ ์๋ น
- ๋์๋ฌธ์ ์ฌ๋ถ์ ์๊ด์์ด xml๋ก ์์ํ๋ฉด ์๋๋ค.
- ์ธ๋ฏธ ์ฝ๋ก ํฌํจ x
- ๋๋ฌธ์ ํฌํจ x
2. csrftoken ์์ฑ
- hidden ํ์
์ผ๋ก ์จ๊ฒจ์ ธ ์๋ csrf๊ฐ์ ๊ฐ์ง input ํ๊ทธ๋ฅผ ์ ํํ๋ค
<!-- accounts/profile.html -->
<script>
const form = document.querySelector("#follow-form");
const csrftoken = document.querySelector("[name=csrfmiddlewaretoken]").value;
</script>
- AJAX๋ก csrftoken ๋ณด๋ด๊ธฐ
<!-- accounts/profile.html -->
<script>
const form = document.querySelector("#follow-form");
form.addEventListener("submit", function (event) {
event.preventDefault();
axios({
method: "post",
url: `/accounts/${userId}/follow/`,
headers: { "X-CSRFToken": csrftoken },
});
});
</script>
- ํ๋ก์ฐ ์ฌ๋ถ๋ฅผ ํ์ธํ ์ ์๋ ๋ณ์๋ฅผ ๋ด์ JSON ํ์ ์ผ๋ก ์๋ตํ๊ธฐ
# accounts/views.py
from django.http import JsonResponse
@require_POST
def follow(request, user_pk):
if request.user.is_authenticated:
User = get_user_model()
me = request.user
you = User.objects.get(pk=user_pk)
if me != you:
if you.followers.filter(pk=me.pk).exists():
you.followers.remove(me)
is_followed = False
else:
you.followers.add(me)
is_followed = True
context = {
'is_followed': is_followed,
}
return JsonResponse(context)
return redirect('accounts:profile', you.username)
return redirect('accounts:login')
- viewsํจ์์์ ์๋ตํ is_followed๋ฅผ ์ฌ์ฉํด ๋ฒํผ ํ ๊ธํ๊ธฐ
<!-- accounts/profile.html -->
<script>
axios({
method: 'post',
url: `/accounts/${userId}/follow/`,
headers: {'X-CSRFToken': csrftoken,}
})
.then((response) => {
const isFollowed = response.data.is_followed
const followBtn = document.querySelector('#follow-form > input[type=submit]')
if (isFollowed === true) {
followBtn.value = '์ธํ๋ก์ฐ'
} else {
followBtn.value = 'ํ๋ก์ฐ'
}
})
- ๊ฐ๋ฐ์ ๋๊ตฌ๋ก ๊ฒฐ๊ณผ ํ์ธํด๋ณด๊ธฐ
ํ๋ก์ & ํ๋ก์ ์ ๋น๋๊ธฐ ์ ์ฉ
- ํด๋น ์์๋ฅผ ์ ํํ ์ ์๋๋ก span ํ๊ทธ์ id ์์ฑ ์์ฑ
<!-- accounts/profile.html -->
{% extends 'base.html' %}
{% block content %}
<h1>{{ person.username }}๋์ ํ๋กํ</h1>
<div>
ํ๋ก์ : <span id="followers-count">{{ person.followers.all|length }}</span> / ํ๋ก์ : <span id="followings-count">{{ person.followings.all|length }}</span>
</div>
- ์ง์ ์ ์์ฑํ span ํ๊ทธ ๊ฐ๊ฐ ์ ํ
<!-- accounts/profile.html -->
<script>
axios({
method: 'post',
url: `/accounts/${userId}/follow/`,
headers: {'X-CSRFToken': csrftoken,}
})
.then((response) => {
...
const followersCountTag = document.querySelector('#followers-count')
const followingsCountTag = document.querySelector('#followings-count')
})
- ํ๋ก์, ํ๋ก์ ์ธ์ ์ ์ฐ์ฐ์ view ํจ์์์ ์งํํ์ฌ ๊ฒฐ๊ณผ๋ฅผ ์๋ต์ผ๋ก ์ ๋ฌ
# accounts/views.py
from django.http import JsonResponse
@require_POST
def follow(request, user_pk):
...
context = {
'is_followed': is_followed,
'followers_count': you.followers.count(),
'followings_count': you.followings.count(),
}
return JsonResponse(context)
return redirect('accounts:profile', you.username)
return redirect('accounts:login')
- view ํจ์์์ ์๋ตํ ์ฐ์ฐ ๊ฒฐ๊ณผ๋ฅผ ์ฌ์ฉํด ๊ฐ ํ๊ทธ์ ์ธ์ ์ ๊ฐ ๋ณ๊ฒฝํ๊ธฐ
<!-- accounts/profile.html -->
<script>
axios({
method: 'post',
url: `/accounts/${userId}/follow/`,
headers: {'X-CSRFToken': csrftoken,}
})
.then((response) => {
...
const followersCountTag = document.querySelector('#followers-count')
const followingsCountTag = document.querySelector('#followings-count')
const followersCount = response.data.followers_count
const followingsCount = response.data.followings_count
followersCountTag.innerText = followersCount
followingsCountTag.innerText = followingsCount
})
์ต์ข ์ฝ๋
- HTML ํ ํ๋ฆฟ
{% extends 'base.html' %}
{% block content %}
<h1>{{ person.username }}๋์ ํ๋กํ</h1>
<div>
ํ๋ก์ : <span id="followers-count">{{ person.followers.all|length }}</span> / ํ๋ก์ : <span id="followings-count">{{ person.followings.all|length }}</span>
</div>
{% if request.user != person %}
<div>
<form id="follow-form" data-user-id="{{ person.pk }}">
{% csrf_token %}
{% if request.user in person.followers.all %}
<input type="submit" value="์ธํ๋ก์ฐ">
{% else %}
<input type="submit" value="ํ๋ก์ฐ">
{% endif %}
</form>
<div>
{% endif %}
- Python ์ฝ๋
@require_POST
def follow(request, user_pk):
if request.user.is_authenticated:
User = get_user_model()
me = request.user
you = User.objects.get(pk=user_pk)
if me != you:
if you.followers.filter(pk=me.pk).exists():
you.followers.remove(me)
is_followed = False
else:
you.followers.add(me)
is_followed = True
context = {
'is_followed': is_followed,
'followers_count': you.followers.count(),
'followings_count': you.followings.count(),
}
return JsonResponse(context)
return redirect('accounts:profile', you.username)
return redirect('accounts:login')
- JavaScript ์ฝ๋
<script>
const form = document.querySelector('#follow-form')
const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value
form.addEventListener('submit', function (event) {
event.preventDefault()
const userId = event.target.dataset.userId
axios({
method: 'post',
url: `/accounts/${userId}/follow/`,
headers: {'X-CSRFToken': csrftoken,}
})
.then((response) => {
// ๋ฒํผ ํ ๊ธ
const isFollowed = response.data.is_followed
const followBtn = document.querySelector('#follow-form > input[type=submit]')
if (isFollowed === true) {
followBtn.value = '์ธํ๋ก์ฐ'
} else {
followBtn.value = 'ํ๋ก์ฐ'
}
// ํ๋ก์ฐ, ํ๋ก์ ์ธ์ ์
const followersCountTag = document.querySelector('#followers-count')
const followingsCountTag = document.querySelector('#followings-count')
const followersCount = response.data.followers_count
const followingsCount = response.data.followings_count
followersCountTag.innerText = followersCount
followingsCountTag.innerText = followingsCount
})
.catch((error) => {
console.log(error.response)
})
})
</script>
์ข์์(like)
โ ํ๋ก์ฐ์ ๋์ผํ ํ๋ฆ + forEach()
& querySelectorAll()
- index ํ์ด์ง ๊ฐ ๊ฒ์๊ธ๋ง๋ค ์ข์์ ๋ฒํผ
- HTML ์ฝ๋
<!-- articles/index.html -->
{% extends 'base.html' %}
{% block content %}
<h1>Articles</h1>
{% if request.user.is_authenticated %}
<a href="{% url 'articles:create' %}">CREATE</a>
{% endif %}
<hr>
{% for article in articles %}
<p>
<b>์์ฑ์ : <a href="{% url 'accounts:profile' article.user %}">{{ article.user }}</a></b>
</p>
<p>๊ธ ๋ฒํธ : {{ article.pk }}</p>
<p>์ ๋ชฉ : {{ article.title }}</p>
<p>๋ด์ฉ : {{ article.content }}</p>
<div>
<form class="like-forms" data-article-id="{{ article.pk }}">
{% csrf_token %}
{% if request.user in article.like_users.all %}
<input type="submit" value="์ข์์ ์ทจ์" id="like-{{ article.pk }}">
{% else %}
<input type="submit" value="์ข์์" id="like-{{ article.pk }}">
{% endif %}
</form>
</div>
<a href="{% url 'articles:detail' article.pk %}">์์ธ ํ์ด์ง</a>
<hr>
{% endfor %}
{% endblock content %}
- Python ์ฝ๋
# articles/views.py
from django.http import JsonResponse
@require_POST
def likes(request, article_pk):
if request.user.is_authenticated:
article = Article.objects.get(pk=article_pk)
if article.like_users.filter(pk=request.user.pk).exists():
article.like_users.remove(request.user)
is_liked = False
else:
article.like_users.add(request.user)
is_liked = True
context = {
'is_liked': is_liked,
}
return JsonResponse(context)
return redirect('accounts:login')
- JavaScript ์ฝ๋
<!-- articles/index.html -->
<script>
const forms = document.querySelectorAll(".like-forms");
const csrftoken = document.querySelector("[name=csrfmiddlewaretoken]").value;
forms.forEach((form) => {
form.addEventListener("submit", function (event) {
event.preventDefault();
// onsole.log(event.target.dataset)
const articleId = event.target.dataset.articleId;
axios({
method: "post",
url: `http://127.0.0.1:8000/articles/${articleId}/likes/`,
headers: { "X-CSRFToken": csrftoken },
})
.then((response) => {
// console.log(response)
// console.log(response.data)
const isLiked = response.data.is_liked;
const likeBtn = document.querySelector(`#like-${articleId}`);
if (isLiked === true) {
likeBtn.value = "์ข์์ ์ทจ์";
} else {
likeBtn.value = "์ข์์";
}
// likeBtn.value = isLiked ? '์ข์์ ์ทจ์' : '์ข์์'
})
.catch((error) => {
console.log(error.response);
});
});
});
</script>
'โญ Personal_Study > Javascript' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์น์์ผ์ ํ์ฉํด ์ค์๊ฐ ์ฑํ ๊ตฌํํ๊ธฐ - React (1) | 2023.05.06 |
---|---|
Axios (0) | 2022.11.05 |
๋๊ธฐ์ ๋น๋๊ธฐ (0) | 2022.11.04 |
Callback & Promise (0) | 2022.11.04 |
JavaScript์์์ This (0) | 2022.11.03 |
๋๊ธ