이 글은 피로그래밍 22기 Django 세션을 위해 작성되었습니다.
1. Django User Model이란?
Django의 User 모델은 사용자 인증과 관리를 위해 제공되는 기본 모델이다. 이 모델은 django.contrib.auth 앱에 포함되어 있으며, 사용자의 계정 정보를 저장하고 인증을 처리하는 역할을 한다.
2. Django User Model 구조
class User(AbstractUser):
"""
Users within the Django authentication system are represented by this
model.
Username and password are required. Other fields are optional.
"""
class Meta(AbstractUser.Meta):
swappable = "AUTH_USER_MODEL"
Django의 기본 User 모델 코드를 보면 AbstractUser만 상속받아 구현되어 있다.
swappable = 'AUTH_USER_MODEL'은 프로젝트에서 settings.AUTH_USER_MODEL을 사용하여 설정을 하면, 기본 사용자 모델을 대체할 수 있게 한다는 의미이다.
AbstractUser 구조 살펴보기
AbstractUser는 AbstractBaseUser와 PermissionsMixin을 상속받아 사용자 정보를 담는 Django의 기본 사용자 모델이다. 주요 필드 및 메소드는 다음과 같다.
class AbstractUser(AbstractBaseUser, PermissionsMixin):
username_validator = UnicodeUsernameValidator()
username = models.CharField(
_("username"),
max_length=150,
unique=True,
help_text=_(
"Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only."
),
validators=[username_validator],
error_messages={
"unique": _("A user with that username already exists."),
},
)
first_name = models.CharField(_("first name"), max_length=150, blank=True)
last_name = models.CharField(_("last name"), max_length=150, blank=True)
email = models.EmailField(_("email address"), blank=True)
is_staff = models.BooleanField(
_("staff status"),
default=False,
help_text=_("Designates whether the user can log into this admin site."),
)
is_active = models.BooleanField(
_("active"),
default=True,
help_text=_(
"Designates whether this user should be treated as active. "
"Unselect this instead of deleting accounts."
),
)
date_joined = models.DateTimeField(_("date joined"), default=timezone.now)
objects = UserManager()
EMAIL_FIELD = "email"
USERNAME_FIELD = "username"
REQUIRED_FIELDS = ["email"]
class Meta:
verbose_name = _("user")
verbose_name_plural = _("users")
abstract = True
def clean(self):
super().clean()
self.email = self.__class__.objects.normalize_email(self.email)
def get_full_name(self):
"""
Return the first_name plus the last_name, with a space in between.
"""
full_name = "%s %s" % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
"""Return the short name for the user."""
return self.first_name
def email_user(self, subject, message, from_email=None, **kwargs):
"""Send an email to this user."""
send_mail(subject, message, from_email, [self.email], **kwargs)
따라서 User의 필드는 다음과 같다.
- username: 사용자 이름, 고유 필드
- email: 이메일 주소
- first_name, last_name: 사용자 이름과 성
- is_staff: 관리자 여부
- is_active: 활성 계정 여부
- is_superuser: 슈퍼유저 여부
- password: 비밀번호 (해싱 저장)
- date_joined: 가입일
여기서 password와 is_superuser는 AbstractBaseUser와 PermissionsMixin에서 제공된다.
User와 AbstractUser의 차이
User와 AbstractUser는 Django에서 사용자 모델을 다룰 때 사용하는 두 가지 클래스이다.
- User: Django의 기본 사용자 모델로, 이미 데이터베이스에 auth_user 테이블이 생성되어 있으며, 바로 사용할 수 있다. 다만, 직접 필드를 수정하거나 추가하는 것은 제한적이다.
- AbstractUser: AbstractBaseUser와 PermissionsMixin을 상속받아 사용자 인증 기능을 제공하는 추상 클래스로, 데이터베이스에 직접 테이블을 생성하지 않으며, 확장을 위한 기반을 제공한다.
User는 상속받지 않는 이유
- 데이터베이스 충돌 가능성: User는 이미 auth_user 테이블을 사용하고 있으며, 상속을 통해 필드를 추가하면 기존 테이블을 직접 수정하게 된다.
- 확장성 부족: User는 이미 정의된 필드만 제공하므로, 사용자 정의 필드를 추가하는 데 제한적이다.
- 공식 권장 방식 아님: Django에서는 AbstractUser를 사용하여 사용자 모델을 커스터마이징하는 것을 권장한다.
이 외의 User, 인증 인가에 대한 부분을 알고 싶다면 https://docs.djangoproject.com/en/5.1/topics/auth/default/를 참고하면 좋을 것 같다.
3. 사용자 모델 확장 (Extending the User Model)
Django에서 사용자 모델을 확장하는 방법은 공식 문서에서 세 가지로 권장된다. https://docs.djangoproject.com/en/5.1/topics/auth/customizing/
1. AbstractUser 상속 사용 (권장)
- AbstractUser를 상속하여 사용자 모델을 직접 확장하는 방식이다.
- AUTH_USER_MODEL을 설정하여 프로젝트 전반에 새로운 사용자 모델을 사용할 수 있도록 한다.
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
phone_number = models.CharField(max_length=15, blank=True)
birth_date = models.DateField(null=True, blank=True)
# settings.py
AUTH_USER_MODEL = 'users.CustomUser' # 앱이름.클래스이름
왼쪽이 아무것도 없을 때 이고, users 앱에 CustomUser를 생성하고, settings.py에 AUTH_USER_MODEL를 등록해 주면 오른쪽처럼 DB 테이블이 생성된다.
AbstractUser를 상속받고 AUTH_USER_MODEL을 설정하면 다음과 같은 데이터베이스 변경이 발생한다.
- 기본 auth_user 테이블 제거 → 새로운 (앱이름_클래스이름) 테이블 생성
- 기존 관계 테이블 대체:
- auth_user_groups → users_customuser_groups
- auth_user_user_permissions → users_customuser_user_permissions
2. OneToOneField를 사용하는 프로필 모델 (간접 확장)
- 기본 User 모델을 유지하고, 프로필 모델을 OneToOneField로 연결한다.
- 데이터베이스 스키마를 수정하지 않고, 추가 데이터를 저장할 수 있다.
from django.contrib.auth.models import User
from django.db import models
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phone_number = models.CharField(max_length=15)
birth_date = models.DateField(null=True, blank=True)
기존 장고 auth_user은 그대로 있고, 이에 일대일대응이되는 users_profile이라는 테이블이 생성된다.
3. Proxy 모델 사용 (기능만 확장, 데이터베이스 변경 없음)
- 데이터베이스 스키마를 변경하지 않고, 기존 User 모델의 기능만 확장할 때 사용한다.
- 새로운 필드를 추가하지 않고, 기존 필드와 테이블을 유지하면서 기능만 추가 가능하다.
from django.contrib.auth.models import User
class CustomUser(User):
class Meta:
proxy = True
def get_full_name_uppercase(self):
return f"{self.first_name} {self.last_name}".upper()
그러나 3번 방법은 거의 사용되지 않으며, 2번 방법도 User 테이블을 굳이 두 개로 나누는 것은 불필요한 리소스 소모가 발생할 수 있기 때문에, 여기서는 가장 많이 사용되는 1번 방법을 사용하여 실습을 진행하려 한다.
4. 실습 (회원가입, 로그인, 로그아웃)
1. 프로젝트 생성 및 User Model 생성
## vscode terminal에서 git bash 사용
# 가상환경 생성
python -m venv venv
# 가상환경 실행 Mac
source venv/bin/activate
# Windows
source venv/Scripts/activate
# Djagno 설치하기
pip install django
# Django 프로젝트 생성
django-admin startproject config .
# 프로젝트 실행 확인
python manage.py runserver
./manage.py runserver
users app 생성
django-admin startapp users
User model 생성
# users/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
GENDER_CHOICE = [
('Male', '남자'),
('Female', '여자'),
]
JOB_CHOICE = [
('Student', '학생'),
('JobSeeker', '취준생'),
('Worker', '직장인'),
('Etc', '기타')
]
name = models.CharField(max_length=10, null=True)
email = models.EmailField() # 이메일을 필수 컬럼으로 재선언
nickname = models.CharField(max_length=20, null=True)
birth = models.DateField(null=True)
gender = models.CharField(max_length=10, choices=GENDER_CHOICE, null=True)
job = models.CharField(max_length=10, choices=JOB_CHOICE, null=True)
desc = models.TextField(max_length=100, blank=True, null=True)
클래스 이름은 꼭 User일 필요는 없다. 각자 알맞게 작성하면 된다.
더 많은 필드와 옵션은 공식문서를 찾아보면 된다. https://docs.djangoproject.com/en/5.1/ref/models/fields/
설정 (앱 등록, User 등록)
# config/settings.py
INSTALLED_APPS = [
...
'users',
]
AUTH_USER_MODEL = 'users.CustomUser'
admin에 등록
# users/admin.py
from django.contrib import admin
from users import models
admin.site.register(models.CustomUser)
DB 생성
python manage.py makemigrations
python manage.py migrate
관리자 계정 생성
python manage.py createsuperuser
개발 서버 실행
python manage.py runserver
# admin 페이지 접속하기 (/admin)
2. User Template 생성
기능별 html 생성
{% comment %} templates/users/main.html 생성 {% endcomment %}
<!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">
<title>Document</title>
</head>
<body>
{% if user.is_authenticated %}
<li><a href="{% url 'users:logout' %}">Logout</a></li>
{% else %}
<li><a href="{% url 'users:login' %}">Login</a></li>
<li><a href="{% url 'users:signup' %}">Signup</a></li>
{% endif %}
{% block content %}
{% endblock content %}
</body>
</html>
{% comment %} templates/users/signup.html 생성 {% endcomment %}
{% extends 'users/main.html' %}
{% block content %}
<form method="POST" action="">
{% csrf_token %}
{{ form }}
<input type="submit" value="SignUp">
</form>
{% endblock content %}
{% comment %} templates/users/login.html 생성 {% endcomment %}
{% extends 'users/main.html' %}
{% block content %}
<form method="POST" action="">
{% csrf_token %}
{{ form }}
<button>Login</button>
</form>
{% endblock content %}
Django Template 문법
{{ }} | 변수 출력 | {{ user.username }} |
{% if %} | 조건문 | {% if user.is_authenticated %} |
{% for %} | 반복문 | {% for user in users %} |
{% comment %} | 주석 | {% comment %} 주석 내용 {% endcomment %} |
{% extends %} | 템플릿 상속 | {% extends 'base.html' %} |
{% block %} | 블록 정의 | {% block content %} {% endblock %} |
{% url %} | URL 연결 | {% url 'login' %} |
{% csrf_token %} | CSRF 보호 | <form>{% csrf_token %}</form> |
{% static %} | 정적 파일 로드 | {% static 'css/style.css' %} |
Django의 폼 렌더링 헬퍼 메서드
{{ form }}은 Django 템플릿에서 사용하는 기본 폼 렌더링 방식이다.
form 객체 전체를 HTML로 렌더링할 때 사용되며, 모든 필드와 라벨을 한 번에 렌더링 한다. {{ form }} 은 다음과 같이 렌더링 된다.
<form method="POST">
<label for="id_username">Username:</label>
<input type="text" name="username" required>
<label for="id_password1">Password:</label>
<input type="password" name="password1" required>
<button type="submit">제출</button>
</form>
그렇다면 {{ form.as_p }} 는 어떻게 렌더링 될까?
<p><label>Username:</label><input type="text"></p>
<p><label>Password:</label><input type="password"></p>
- form.as_p → <p> 태그로 감싸서 폼을 자동 렌더링
- form.as_ul → <ul> 및 <li> 태그 사용
- form.as_table → <table> 태그 사용
- 사용자 정의 렌더링 → 직접 태그를 작성하여 폼을 커스터마이징 -> {{ form.username }}
VScode에서 Django html을 사용할 경우 확장프로그램 Django를 설치해주고 우측 아래 HTML을 클릭 후 Django HTML을 설정해 주면 Django Template 문법을 인식해 준다.
settings.py 추가하기
# config/settings.py
import os
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [os.path.join(BASE_DIR, "templates")],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
TEMPLATES 설정은 Django에서 템플릿 엔진을 정의하는 부분이다.
이 설정을 통해 HTML 파일 위치, 템플릿 로딩 방식, 컨텍스트 프로세서 등을 지정할 수 있다.
- 우리가 변경한 DIRS는 템플릿 파일의 경로를 명시적으로 지정하는 옵션이다.
- [os.path.join(BASE_DIR, "templates")]는 프로젝트의 루트 디렉터리(BASE_DIR) 아래 templates 폴더를 템플릿 디렉터리로 사용하겠다는 의미이다. (예를 들면 project/app/templates 폴더를 사용하겠다는 의미이다.)
3. User View 생성
Django의 Form이란?
Form은 Django에서 사용자 입력 데이터를 다루기 위한 도구로, HTML 폼을 Python 코드로 표현할 수 있게 해 준다. 이를 통해 유효성 검사(Validation), 데이터 저장, 입력 필드 정의 등을 간편하게 처리할 수 있다.
Form의 주요 기능
- 데이터 유효성 검사: 사용자가 입력한 데이터가 유효한지 검증한다.
- 데이터 렌더링: 폼을 HTML로 변환하여 웹 페이지에 출력한다.
- 데이터 저장: 데이터베이스에 사용자 데이터를 저장한다.
보통 forms.py를 생성해서 form을 사용한다. 물론 forms.py 외에도 Django에서 폼을 생성할 수 있다. 하지만 forms.py에 폼을 작성하는 것이 일반적으로 권장되는 이유는 유지보수성과 코드의 가독성 때문이다.
Django의 Built-in Form (내장 폼)
Django는 기본 제공 auth 폼을 제공하여 일반적인 사용자 관리를 지원한다.
AbstractBaseUser와 호환되는 내장 폼
- AuthenticationForm: 사용자 로그인에 사용한다. (USERNAME_FIELD를 사용)
- SetPasswordForm: 사용자가 비밀번호를 재설정할 때 사용한다.
- PasswordChangeForm: 사용자가 비밀번호를 변경할 때 사용한다.
- AdminPasswordChangeForm: 관리자가 비밀번호를 변경할 때 사용한다.
User 모델과 직접 연관된 내장 폼
- UserCreationForm: 사용자 회원가입 폼
- UserChangeForm: 사용자 정보 수정 폼
- PasswordResetForm: 비밀번호 재설정 폼 (이메일 기반)
# users/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from .models import CustomUser
# 회원가입 폼
class SignupForm(UserCreationForm):
class Meta:
model = CustomUser
fields = ['username', 'password1', 'password2', 'email', 'name', 'nickname', 'birth', 'gender', 'job', 'desc']
- UserCreationForm 상속: Django의 기본 회원가입 폼을 확장한다.
- Meta 클래스: CustomUser 모델과 연결한다.
- fields 정의: 사용자명, 비밀번호, 이메일, 이름, 닉네임, 생년월일, 성별 등 회원가입에 필요한 필드들을 작성한다.
view 생성 (FBV 방식)
# users/views.py
from django.shortcuts import render, redirect
from users.forms import SignupForm
from django.contrib.auth.forms import AuthenticationForm
from django.contrib import auth
def main(request):
return render(request, "users/main.html")
def signup(request):
if request.method == 'POST':
form = SignupForm(request.POST)
if form.is_valid():
user = form.save()
auth.login(request, user)
return redirect('users:main')
else:
return redirect('users:signup')
else:
form = SignupForm()
context = {
'form': form,
}
return render(request, template_name='users/signup.html', context=context)
def login(request):
if request.method == 'POST':
form = AuthenticationForm(request, request.POST)
if form.is_valid():
user = form.get_user()
auth.login(request, user)
return redirect('users:main')
else:
context = {
'form':form,
}
return render(request, template_name='users/login.html',context=context)
else:
form = AuthenticationForm()
context = {
'form': form,
}
return render(request, template_name='users/login.html', context=context)
def logout(request):
auth.logout(request)
return redirect('users:main')
main 뷰
이 뷰는 메인 페이지를 렌더링 한다. 사용자가 GET 요청을 보낼 때 메인 템플릿을 보여준다.
signup 뷰
이 뷰는 회원가입을 처리한다.
- POST 요청 시, SignUpForm 데이터를 검증하고 저장한 후 로그인 처리한다.
- GET 요청 시, 빈 폼을 보여준다.
login 뷰
이 뷰는 로그인을 처리한다.
- POST 요청 시, AuthenticationForm을 사용해 사용자 자격을 확인하고 로그인 처리한다.
- GET 요청 시, 빈 로그인 폼을 렌더링한다.
logout 뷰
이 뷰는 로그아웃을 처리한다. auth.logout()을 사용하여 사용자의 세션을 종료하고 메인 페이지로 리다이렉트 한다.
FBV(Function Based View) vs CBV(Class Based Views)
FBV (Function-Based View) - 함수 기반 뷰
Python의 일반 함수를 사용하여 HTTP 요청을 처리하는 방식이다. 요청이 들어오면 특정 함수를 호출하고, 해당 함수가 요청을 분석하여 적절한 응답을 반환한다. 코드를 이해하기 쉽고, 간단한 로직을 작성하는 데 매우 직관적이다.
장점: 코드가 단순하고 직관적이며, 빠르게 개발 가능하다.
단점: 복잡한 로직을 처리하거나 재사용할 때 코드가 길어지고 유지보수가 어려워질 수 있다.
CBV (Class-Based View) - 클래스 기반 뷰
Python 클래스를 사용하여 HTTP 요청을 처리하는 방식이다. 뷰를 메서드로 나누어 각 HTTP 메서드(GET, POST 등)에 대해 별도의 메서드를 정의할 수 있다. Django의 View 클래스를 상속받아 사용하며, 보다 구조화된 코드 작성을 가능하게 한다.
장점: 코드의 재사용성이 높고, 뷰를 더 세분화하여 작성할 수 있다.
단점: 코드가 다소 복잡하고, 초보자가 이해하기 어려울 수 있다.
이번 실습은 아직 입문하는 단계여서 코드가 직관적이고 간단한 FBV 방식을 선택했다.
렌더링과 리다이렉트의 차이
Django에서 렌더링과 리다이렉트는 웹 페이지를 사용자에게 보여주는 방식에서 중요한 역할을 한다. 이 둘은 기능적으로 비슷해 보일 수 있지만, 사용하는 목적과 동작 방식에서 명확한 차이가 있다.
렌더링 (Rendering)
렌더링은 서버에서 HTML 파일을 브라우저에 직접 변환하여 보여주는 과정이다. render() 함수를 사용하며, 주로 데이터를 사용자에게 즉시 보여줄 때 사용한다. 예를 들어, 회원가입 폼을 표시하거나, 데이터 입력 폼을 제출한 후 에러 메시지를 다시 표시할 때 사용된다.
- 데이터 유지: 렌더링은 현재 페이지에서 데이터를 유지하면서 화면을 갱신한다.
- 즉시 표시: 데이터를 화면에 바로 보여주기 적합하다.
- ex) 에러 메시지 표시, 폼 다시 보여주기
리다이렉트 (Redirect)
리다이렉트는 사용자를 다른 URL로 이동시키는 방식이다. redirect() 함수를 사용하며, 사용자가 데이터를 변경한 후 페이지를 새로고침하거나 다른 뷰로 이동할 때 사용된다. 예를 들어, 회원가입이나 로그인 성공 후 메인 페이지로 이동할 때 사용된다.
- 데이터 유지 불가: 리다이렉트는 새로운 요청을 생성하므로 데이터가 초기화된다.
- 페이지 이동: 사용자를 다른 페이지로 이동시킬 때 유용하다.
- ex) 회원가입, 로그인 후 페이지 이동
4. User URL 연결
# config/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('users.urls')),
]
# users/urls.py 생성
from django.urls import path
from . import views
app_name = "users"
urlpatterns = [
path("", views.main, name="main"),
path("signup/", views.signup, name="signup"),
path("login/", views.login, name="login"),
path("logout/", views.logout, name="logout"),
]
http://127.0.0.1:8000/ 실제 개발 서버에서 테스트해보자.
5. Form Custom
from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import CustomUser
class SignupForm(UserCreationForm):
# 성별 선택지를 정의 (드롭다운에 표시될 값)
GENDER_CHOICES = [
('Male', '남자'),
('Female', '여자'),
]
# 직업 선택지를 정의 (드롭다운에 표시될 값)
JOB_CHOICES = [
('Student', '학생'),
('Worker', '직장인'),
('JobSeeker', '취준생'),
('Other', '기타'),
]
# 사용자명 입력 필드 (텍스트 입력 필드, CSS 클래스 추가)
username = forms.CharField(
label="아이디", # 폼에서 표시될 라벨
widget=forms.TextInput(attrs={'class': 'form-control'}) # Bootstrap 스타일 적용
)
# 이메일 입력 필드 (이메일 유효성 검사 포함)
email = forms.EmailField(
label="이메일",
widget=forms.EmailInput(attrs={'class': 'form-control'})
)
# 비밀번호 입력 필드 (마스킹 처리, 비밀번호 입력 전용)
password1 = forms.CharField(
label="비밀번호",
widget=forms.PasswordInput(attrs={'class': 'form-control'})
)
# 비밀번호 확인 입력 필드 (비밀번호 재확인용)
password2 = forms.CharField(
label="비밀번호 확인",
widget=forms.PasswordInput(attrs={'class': 'form-control'})
)
# 성별 선택 필드 (드롭다운 선택, GENDER_CHOICES 사용)
gender = forms.ChoiceField(
choices=GENDER_CHOICES, # 위에서 정의한 성별 선택지 사용
label="성별",
widget=forms.Select(attrs={'class': 'form-control'})
)
# 직업 선택 필드 (드롭다운 선택, JOB_CHOICES 사용)
job = forms.ChoiceField(
choices=JOB_CHOICES, # 위에서 정의한 직업 선택지 사용
label="직업",
widget=forms.Select(attrs={'class': 'form-control'})
)
# 자기소개 필드 (여러 줄 텍스트 입력, 선택 입력 가능)
bio = forms.CharField(
label="자기소개",
widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3}), # 텍스트 영역 스타일 적용
required=False # 필수 입력 아님
)
# Meta 클래스: 폼의 설정을 정의
class Meta:
model = CustomUser # 이 폼이 연결될 데이터베이스 모델
fields = ['username', 'email', 'password1', 'password2', 'gender', 'job', 'bio'] # 폼에 포함될 필드 목록
# help_texts: 각 필드의 기본 도움말 제거
help_texts = {
'username': None, # 사용자명 도움말 제거
'password1': None, # 비밀번호 도움말 제거
'password2': None, # 비밀번호 확인 도움말 제거
'email': None # 이메일 도움말 제거
}
# 이메일 중복 검사 메소드 (clean_email)
def clean_email(self):
# 사용자가 입력한 이메일 데이터 가져오기
email = self.cleaned_data.get('email')
# 데이터베이스에 동일한 이메일이 존재하는지 검사
if CustomUser.objects.filter(email=email).exists():
# 이미 존재하면 유효성 오류 발생
raise forms.ValidationError("이미 사용 중인 이메일입니다.")
# 유효한 경우 이메일 반환
return email
위와 같이 Form에 내장되어 있는 주요 기능들이 있다. 이 외에도 다양한 옵션들이 있으니 각 상황에 맞게 찾아서 사용하면 된다.
def signup(request):
if request.method == 'POST':
form = SignupForm(request.POST)
if form.is_valid():
user = form.save()
auth.login(request, user)
return redirect('users:main')
else:
# return redirect('users:signup')
return render(request, 'users/signup.html', {'form': form})
else:
form = SignupForm()
context = {
'form': form,
}
return render(request, template_name='users/signup.html', context=context)
이렇게 에러 메시지를 회원가입 화면에서 표시하고 싶으면 form.is_valid()되지 않을 때 redirect가 아닌 render를 통해 form의 정보를 signup.html으로 보낸다.
따라서 다음과 같은 에러 메세지를 확인하면 오늘 실습을 잘 따라온 것 입니다!
사실 요즘에는 이런 방식의 회원가입과 로그인을 사용하는 경우가 드뭅니다. 대부분 소셜 로그인(Kakao, Naver, Google 등)을 기반으로 사용자 인증을 처리하고 있습니다. 하지만 이러한 기초를 잘 이해해야만 소셜 로그인을 응용할 수 있기 때문에 먼저 이 글을 완벽히 이해한 후 소셜 로그인으로 넘어가 보길 바랍니다.
추가로 서버에 관심이 있을 분들을 위해 생각해보면 좋을 것들 같이 적어두겠습니다. (이거 말고도 스스로 생각해봐도 좋을 것 같습니다. 그리고 지금까지 모든 장고 세션을 정말 다 이해했다 했을 경우에만 추가로 더 공부해주세요. 이전의 기초 내용을 알지 못한 채 넘어간다면 정말 의미가 없습니다🥹)
우선 Kakao 소셜 로그인 관련해서 링크 올려두겠습니다. 참고하면 좋을 것 같습니다.
https://clownhacker.tistory.com/172
하지만 이 블로그의 코드는 정답이 아닙니다.
- 소셜 로그인 구현 방식은 다양합니다.
- 각 방식의 장단점을 비교하고, 자신의 프로젝트에 맞는 방식을 선택하세요.
- 물론 지금은 구현하기 쉬운 하나를 택해서 이해하는 것이 제일 좋을 것 같습니다.
소셜 로그인 1개만 공부해도 충분합니다!
- 한 개의 소셜 로그인을 완벽히 이해하면 나머지(Naver, Google 등..)도 거의 동일한 방식으로 적용할 수 있습니다.
- 하나를 완벽하게 이해하는 것도 매우 어렵습니다.
더 나아가서 커스텀 User 모델을 소셜 로그인으로 구현하는 방법까지 생각해보면 좋을 것 같습니다.
- 사용자가 동의하지 않는 정보까지 받아야 하는 경우, 커스텀 User 모델을 활용하여 직접 추가 정보를 저장할 수 있습니다. 이런 경우도 실제로 많기 때문에 소셜 로그인을 활용해서 구현해보세요.
여러 방향성을 고려하고, 자신만의 방식으로 확장해보세요! 다들 화이팅입니다! 🚀
추가로 저도 이 세션을 준비하면서 Django 관련해서 글을 몇 개 작성했고, 이번 주 내로 알면 좋을 내용들을 몇 개 더 올릴 예정입니다. 혹시나 백엔드 개발에 관심이 있거나, Django에 대해 더 알아보고 싶다 하면 참고해주시면 좋을 것 같습니다 :)
'Django' 카테고리의 다른 글
[Django] Django 프로세스, Request-Response Lifecycle (Web Server, WSGI/ASGI, Middlewares, Django) (1) | 2025.01.24 |
---|---|
[Django] URL dispatcher 공식 문서 파헤치기 (1) | 2025.01.18 |
[Django] settings.py 완전 정복 (..파일 분리까지) (0) | 2025.01.11 |
[Django] Django 마이그레이션과 MySQL 활용 (0) | 2025.01.10 |
[Django] Django란? + 기초 실습 (1) | 2025.01.04 |