이번에 새로 프로젝트를 진행하며 Django로 백엔드를 구현하게 되었다.
스프링을 계속 다루다 보니 많이 익숙해져서 새로운 자극이 필요했는데 마침 잘됐다 싶어 Django 백엔드 제안을 수락했다.
Django는 처음 다뤄보기에 배우는 내용을 기록에 남겨두려고한다.
또 장고는 FBV와 CBV 로 나눠지는데 이번 프로젝트는 일단 쉽고 간편하게 쓸 수 있는 FBV(Fuction-Base Views) 로 진행해보았다.
다음에 또 장고를 진행하게된다면 그 땐 CBV 도 써봐야겠다.
Django 프로젝트 생성
pip install django
django-admin startproject [프로젝트명]
위 명령어를 통해 프로젝트를 생성
MySql과 연동
필자는 MySql을 사용할 예정이라 먼저 연동을 하고 시작함.
pip install mysqlclient
프로젝트 최상단에 secrets.json을 만들어 DB정보와 키값을 따로 관리
// secrets.json
{
"SECRET_KEY": "Django SecretKey",
"DATABASES": {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": "DB이름",
"USER": "아이디",
"PASSWORD": "비밀번호",
"HOST": "127.0.0.1",
"PORT": "3306"
}
},
}
settings.py 에 secrets.json 추가
# settings.py
# 숨겨둔 키를 불러오는 코드
from pathlib import Path
import json
import sys
BASE_DIR = Path(__file__).resolve().parent.parent
ROOT_DIR = os.path.dirname(BASE_DIR)
SECRET_BASE_FILE = os.path.join(BASE_DIR, 'secrets.json')
secrets = json.loads(open(SECRET_BASE_FILE).read())
for key, value in secrets.items():
setattr(sys.modules[__name__], key, value)
# 여기까지
# 언어와 시간정보도 바꿔두자 !
LANGUAGE_CODE = 'ko'
TIME_ZONE = 'Asia/Seoul'
USE_I18N = True
USE_L10N = True
USE_TZ = False
유저 모델이 들어갈 앱 생성
python manage.py startapp accounts
DRF와 JWT 관련 세팅
pip install djangorestframework djangorestframework-simplejwt
위 명령어를 통해 필요한 라이브러리 설치
JWT 라이브러리는 django-rest-framework-jwt 와 djangorestframework-simplejwt 가 있는데,
djangorestframework-jwt 라이브러리는 더 이상 업데이트되지 않고,
DRF 공식문서에도 djangorestframework-simplejwt 사용을 권장하기에 SimpleJWT로 진행하였다.
settings.py 에 아래와 같이 추가
# settings.py
INSTALLED_APPS = [
...
'rest_framework',
'rest_framework_simplejwt',
'accounts',
...
]
AUTH_USER_MODEL = 'accounts.User' # 커스텀 유저를 장고에서 사용하기 위함
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated', # 인증된 요청인지 확인
'rest_framework.permissions.IsAdminUser', # 관리자만 접근 가능
'rest_framework.permissions.AllowAny', # 누구나 접근 가능
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication', # JWT를 통한 인증방식 사용
),
}
REST_USE_JWT = True
from datetime import timedelta
SIMPLE_JWT = {
'SIGNING_KEY': secrets["SECRET_KEY"],
'ACCESS_TOKEN_LIFETIME': timedelta(hours=1),
'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
'ROTATE_REFRESH_TOKENS': False,
'BLACKLIST_AFTER_ROTATION': True,
}
커스텀 유저 모델 생성
아이디를 대신해서 이메일을 사용하고, username을 name으로 변경
프로필 이미지를 추가하기 위해 모델에 프로필 이미지와 관련된 모델을 추가로 생성하였다.
https://dev-yakuza.posstree.com/ko/django/custom-user-model/ 을 참고해서 생성하였다.
accounts/model.py 수정
# accounts/model.py
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
class UserManager(BaseUserManager):
def create_user(self, email, name, password=None):
user = self.model(
email=self.normalize_email(email),
name=name,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, name, password):
user = self.create_user(
email,
name=name,
password=password,
)
user.is_admin = True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
email = models.EmailField(
verbose_name='email',
max_length=100,
unique=True,
)
name = models.CharField(max_length=30)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
@property
def is_staff(self):
return self.is_admin
class Meta:
db_table = 'user' # 테이블명을 user로 설정
DRF를 위한 serializers.py 생성
# accounts/serializers.py
from django.contrib.auth.models import User
from rest_framework import serializers
from django.contrib.auth import get_user_model
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
class Meta:
model = get_user_model()
fields = ('id', 'email', 'password', 'name')
# 패스워드가 필요없는 다른 테이블에서 사용할 용도
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ('id', 'email', 'name')
REST API를 위한 view 작성
회원가입과 로그인만 작성해두었다.
로그인은 simplejwt 에서 제공하는 token_obtain_pair을 이용해도 되지만 해당 view를 이용하면 DB에 last_login은 따로 초기화되지 않아서(어드민 페이지에서 로그인 시에만 초기화됨) 따로 login을 구성하였다.
# accounts/views.py
from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken
from django.contrib.auth import authenticate
from django.contrib.auth.models import update_last_login
from accounts.serializers import UserSerializer
@api_view(['POST'])
@permission_classes([AllowAny])
def signup(request):
email = request.data.get('email')
password = request.data.get('password')
name = request.data.get('name')
serializer = UserSerializer(data=request.data)
serializer.email = email
serializer.name = name
if serializer.is_valid(raise_exception=True):
user = serializer.save()
user.set_password(password)
user.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
@api_view(['POST'])
@permission_classes([AllowAny])
def login(request):
email = request.data.get('email')
password = request.data.get('password')
user = authenticate(email=email, password=password)
if user is None:
return Response({'message': '아이디 또는 비밀번호가 일치하지 않습니다.'}, status=status.HTTP_401_UNAUTHORIZED)
refresh = RefreshToken.for_user(user)
update_last_login(None, user)
return Response({'refresh_token': str(refresh),
'access_token': str(refresh.access_token), }, status=status.HTTP_200_OK)
URL 연결
# urls.py
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
path('api/user/', include('accounts.urls')),
]
# accounts/urls.py
from django.urls import include, path
from . import views
login_patterns = [
path('normal/', views.login, name='login'),
]
urlpatterns = [
path('signup/', views.signup, name='signup'),
path('login/', include(login_patterns)),
]
어드민 페이지에 등록
# accounts/admin.py
from django.contrib import admin
from .models import User
admin.site.register(User)
마이그레이션 진행
python manage.py makemigrations
python manage.py migrate
어드민 계정 생성
여기까지 했다면 어드민 계정을 먼저 생성해보자
명령어를 통해 생성하면 Email을 이제 먼저 입력받는 것을 확인할 수 있다.
python manage.py runserver 를 통해 서버를 실행하고
http://localhost:8000/admin/ 을 통해 어드민 페이지에 접근해 방금 생성한 아이디로 로그인해보자
로그인 후 메인 페이지에 아까 등록한 User 를 확인할 수 있다.
눌러보면 방금 생성했던 admin 계정이 있는 것까지 확인 가능하다.
REST API로 유저 회원가입
api 테스트는 postman을 이용해서 진행했다.
잘 작동됨을 확인할 수 있다.
REST API로 유저 로그인
로그인 시에는 jwt token이 잘 받아와 지는지 확인해야 한다.
토큰이 잘 받아와 지는 것을 확인할 수 있다.
또 의도한 대로 DB에 마지막 로그인 시간도 잘 입력됨을 확인할 수 있다.
다음 시간에는 JWT 토큰을 이용해서 공지사항을 만들어보려고 한다.
어드민 유저만 공지사항 작성 및 수정 API에 접근이 가능하고,
조회는 아무나 가능하게끔 권한을 주는 법을 배워보자 !
'Backend > Django' 카테고리의 다른 글
[Django-DRF] drf-yasg 를 활용한 Swagger 적용하기 (0) | 2022.03.13 |
---|---|
[Django-DRF] REST API를 이용한 CRUD 구현 with JWT, Pagination (0) | 2022.03.03 |