1) Messages Tag
- Django์ Messages Framework๋ฅผ ํตํด ์์ธ์ฒ๋ฆฌ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ๋ ๋ง๋ค ํ
ํ๋ฆฟ์ ๋ํ๋ผ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ์์ฝ๊ฒ ์ ์ดํ ์ ์์ด์. ๋ด์ฅ๋์ด ์๊ธฐ ๋๋ฌธ์ Project๋ฅผ ์ค์นํ ๋ ๋ถํฐ ์ฌ์ฉํ ์ ์๊ณ , ์๋์ ๊ฐ์ ํ๊ทธ๋ค์ด ์ค๋น๋์ด ์์ด์.
messages.debug(request, '%s SQL statements were executed.' % count)
messages.info(request, 'Three credits remain in your account.')
messages.success(request, 'Profile details updated.')
messages.warning(request, 'Your account expires in three days.')
messages.error(request, 'Document deleted.')
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li class="message {% if message.tags %}{{ message.tags }}{% endif %}">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
2) using messages
- Messages Framework์ ์๋ ์์นํด ์์ด์.
- ๐ from django.contrib import messages
- ๊ฐ ์๋ฌ ๋ด์ฉ์ ๋ง๊ฒ ์๋ฌ ์์ ๋ํ๋ผ ๋ฉ์์ง๋ฅผ ๋ด๊ณ , except ๊ตฌ๋ฌธ์์ ํด๋น ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด ์์ฑํ ๋ฉ์์ง๋ฅผ ์ ๋ฌํฉ๋๋ค.
- ๐ messages.error(request, e)
- ์ฑ๊ณต๋ฉ์์ง๋ login() ๋งค์๋ ๋ฐ๋ก ์๋ ์ถ๊ฐํ์์ด์:)
import os
import requests
from django.views.generic import FormView
from django.urls import reverse_lazy
from django.shortcuts import render, redirect, reverse
from django.contrib.auth import authenticate, login, logout
from django.core.files.base import ContentFile
from django.contrib import messages
from . import forms, models
...
...
def log_out(request):
messages.info(request, f"See you later")
logout(request)
return redirect(reverse("core:home"))
def github_login(request):
client_id = os.environ.get("GITHUB_ID")
redirect_uri = "http://127.0.0.1:8000/users/login/github/callback"
return redirect(
f"https://github.com/login/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&scope=read:user"
)
class GithubException(Exception):
pass
def github_callback(request):
try:
client_id = os.environ.get("GITHUB_ID")
client_secret = os.environ.get("GITHUB_SECTET")
code = request.GET.get("code", None)
if code is not None:
token_request = requests.post(
f"https://github.com/login/oauth/access_token?client_id={client_id}&client_secret={client_secret}&code={code}",
headers={"Accept": "application/json"},
)
token_json = token_request.json()
error = token_json.get("error", None)
if error is not None:
raise GithubException("Can't get authoriztion code.")
else:
access_token = token_json.get("access_token")
profile_request = requests.get(
"https://api.github.com/user",
headers={
"Authorization": f"token {access_token}",
"Accept": "application/json",
},
)
profile_json = profile_request.json()
username = profile_json.get("login", None)
if username is not None:
name = profile_json.get("name")
email = profile_json.get("email")
bio = profile_json.get("bio")
try:
user = models.User.objects.get(email=email)
if user.login_method != models.User.LOGIN_GITHUB:
raise GithubException(
f"Please log in with : {user.login_method}"
)
except models.User.DoesNotExist:
user = models.User.objects.create(
email=email,
first_name=name,
username=email,
bio=bio,
login_method=models.User.LOGIN_GITHUB,
email_verified=True,
)
user.set_unusable_password()
user.save()
login(request, user)
messages.success(request, f"Welcome back! {user.first_name}")
return redirect(reverse("core:home"))
else:
raise GithubException("Can't get your profile")
else:
raise GithubException("Can't get code")
except GithubException as e:
messages.error(request, e)
return redirect(reverse("users:login"))
def kakao_login(request):
client_id = os.environ.get("KAKAO_ID")
redirect_uri = "http://127.0.0.1:8000/users/login/kakao/callback"
return redirect(
f"https://kauth.kakao.com/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code"
)
class KakaoException(Exception):
pass
def kakao_callback(request):
try:
code = request.GET.get("code")
client_id = os.environ.get("KAKAO_ID")
redirect_uri = "http://127.0.0.1:8000/users/login/kakao/callback"
token_request = requests.get(
f"https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id={client_id}&redirect_uri={redirect_uri}&code={code}"
)
token_json = token_request.json()
error = token_json.get("error", None)
if error is not None:
raise KakaoException("Can't get authoriztion code.")
access_token = token_json.get("access_token")
profile_request = requests.get(
"https://kapi.kakao.com//v2/user/me",
headers={"Authorization": f"Bearer {access_token}"},
)
profile_json = profile_request.json()
email = profile_json.get("kakao_account").get("email")
if email is None:
raise KakaoException("Please also give me your email")
properties = profile_json.get("kakao_account").get("profile")
nickname = properties.get("nickname")
profile_image = properties.get("profile_image_url")
print(nickname, profile_image)
try:
user = models.User.objects.get(email=email)
if user.login_method != models.User.LOGIN_KAKAO:
raise KakaoException(f"Please log in with : {user.login_method}")
except models.User.DoesNotExist:
user = models.User.objects.create(
email=email,
first_name=nickname,
username=email,
login_method=models.User.LOGIN_KAKAO,
email_verified=True,
)
user.set_unusable_password()
user.save()
if profile_image is not None:
photo_request = requests.get(profile_image)
user.avatar.save(
f"{nickname}-avatar", ContentFile(photo_request.content)
)
login(request, user)
messages.success(request, f"Welcome back {user.first_name}")
return redirect(reverse("core:home"))
except KakaoException as e:
messages.error(request, e)
return redirect(reverse("users:login"))
3) Design Messages
- ๋ฉ์์ง๊ฐ ์๋จ์ ๋
ธ์ถ๋๋๋ก, "partials/messages.html"์ด "base.html" head ์์ ๋ฐฐ์นํ์ด์:)
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{% static 'css/styles.css' %}">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.11.2/css/all.css">
<title>{% block page_title %}{% endblock page_title %}| Nbnb</title>
</head>
<body class="text-gray-800 mt-24 font-light">
{% include "partials/messages.html" %}
<header class="container max-w-full inset-0 flex items-center justify-between px-6 h-20 border-b border-gray-400 fixed bg-white">
<div class="flex items-center w-1/3">
<a href="{% url "core:home" %}" class="mr-6">
<img class="w-8" src="{% static 'img/airbnb_logo.png' %}">
</a>
{% block search-bar %}
<form method="get" action="{% url "rooms:search" %}" class="w-9/12">
<input class="search-box border px-5 w-full font-medium text-gray-900 placeholder-gray-600 py-3 rounded-sm shadow-md hover:shadow-lg focus:outline-none" name="city" placeholder="Search by City" type="text">
</form>
{% endblock search-bar %}
</div>
{% include "partials/nav.html" %}
</header>
{% block content %}{% endblock content %}
{% include "partials/footer.html" %}
</body>
</html>
- "partials/messages.html"์ TailwindCSS๋ฅผ ์ ์ฉ์์ผ๋ณผ๊ป์.
{% if messages %}
<ul class="absolute top-0 mx-auto left-0 right-0 flex justify-center">
{% for message in messages %}
<li class="message font-medium bg-gray-700 z-10 rounded-full text-white py-4 px-6 w-64 text-center {% if message.tags %}{{ message.tags }}{% endif %}">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
- Message Tag ๋ณ๋ก ์๊น์ ๋ค๋ฅด๊ฒ์ฃผ๊ณ , ์ ๋๋ฉ์ด์
ํจ๊ณผ๋ ์๋์ฒ๋ผ ๋ฃ์ ์ ์์ต๋๋ค:)
@tailwind base;
@tailwind components;
@tailwind utilities;
...
...
...
@keyframes messageFadeIn {
0% {
opacity: 0;
transform: translateY(-50px);
}
5% {
opacity: 1;
transform: translateY(50px);
}
95% {
opacity: 1;
transform: translateY(50px);
}
100% {
opacity: 0;
transform: translateY(-50px);
}
}
.message{
animation: messageFadeIn 5s ease-in-out forwards;
&.error{
@apply bg-red-600;
}
&.info{
@apply bg-blue-500;
}
&.success{
@apply bg-green-500;
}
&.warning{
@apply bg-yellow-400;
}
}