Django에서는 기본적으로 제공하는 User 모델이 있지만, 대부분의 프로젝트에서는 사용자 모델을 확장하여 추가적인 기능을 구현
AUTH_USER_MODEL 설정을 변경하여 기본 User Model을 대체할 수 있으며, 프로젝트 초기부터 Custom User Model을 적용하는 것이 권장됨
- AUTH_USER_MODEL 설정은 프로젝트 최초 마이그레이션에서 함께 진행하기를 권장
- USER Model은 비지니스로직 깊숙이 관여됨 → 중간에 변경 시 많은 변경사항을 야기
Custom User Model 적용
User 모델 정의
accounts/models.py에서 Django의 기본 AbstractUser를 상속받아 Custom User Model을 정의
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
기본 User 모델을 변경하지 않더라도 확장성을 높일 수 있음
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
groups = models.ManyToManyField(
"auth.Group",
related_name="custom_user_set", # 기본값 'user_set' 대신 변경
blank=True
)
user_permissions = models.ManyToManyField(
"auth.Permission",
related_name="custom_user_permissions_set", # 기본값 'user_set' 대신 변경
blank=True
)

- groups와 user_permissions 필드에서 related_name을 변경하지 않으면 Django 기본 User 모델과 충돌이 발생할 수 있음
settings.py 사용자 모델 설정
Django 프로젝트에서 기본 사용자 모델을 교체하려면 AUTH_USER_MODEL 설정을 추가해야 함
# settings.py
...
AUTH_USER_MODEL = 'accounts.User'
...
→ Django는 accounts.User 모델을 기본 User 모델로 인식

관리자 페이지에 Custom User Model 등록
accounts/admin.py에서 사용자 모델을 Django 관리자 페이지에서 사용할 수 있도록 등록

User 모델 마이그레이션 적용
User 모델을 변경하는 것은 프로젝트에 큰 영향을 미치므로, 반드시 프로젝트 초기에 설정하는 것이 좋음
이미 진행된 프로젝트에서 변경하는 경우, 기존 데이터베이스를 초기화해야 할 수도 있음
# 기존 마이그레이션 파일 삭제
rm -rf accounts/migrations
# 데이터베이스 초기화
rm db.sqlite3 # SQLite를 사용하는 경우
# 새로운 마이그레이션 파일 생성 및 적용
python manage.py makemigrations accounts
python manage.py migrate
회원가입 폼 수정
Django의 기본 UserCreationForm은 기존의 User 모델 사용
→ 새로 정의한 User 모델을 바라보도록 상속하여 수정
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import get_user_model
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = get_user_model()
fields = UserCreationForm.Meta.fields + ("추가필드",) # 필요한 필드를 추가할 수 있음

회원가입 view의 Form 변경

1:N 관계 확장하기
게시글과 사용자 간의 관계를 1:N으로 확장하여, 작성자를 명확히 구분할 수 있도록 설정
User(1) - Article(N) 관계 설정
articles/models.py - 작성자 필드 추가
게시글 모델(Article)에 author 필드를 추가하여 작성자 저장
from django.db import models
from django.conf import settings
class Article(models.Model):
title = models.CharField(max_length=255)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
# 작성자 필드 추가
author = models.ForeignKey(
settings.AUTH_USER_MODEL, # Custom User 모델을 참조
on_delete=models.CASCADE, # 작성자가 삭제되면 관련 게시글도 삭제됨
related_name="articles"
)

각 게시글이 특정 사용자와 연결되며, User 모델을 참조하여 1:N 관계를 유지하게 됨
*댓글 모델 확장
게시글뿐만 아니라 댓글도 작성자를 저장하여 1:N 관계를 확장가능
댓글 기능 추가
- 로그인한 사용자만 댓글을 작성할 수 있도록 제한
- 댓글 작성자만 댓글을 삭제할 수 있도록 설정
- 댓글 작성자에게만 삭제 버튼 표시
articles/article_detail.html
{% extends 'base.html' %}
{% block title %}ARTICLE_DETAIL{% endblock title %}
{% block content %}
<h2>{{ article.title }}</h2><br>
<p>작성자 : {{ article.author.username }}</p>
{% if article.image %}
<img src="{{ article.image.url }}">
{% endif %}
<p>{{ article.content }}</p><br>
<p>작성일시 : {{ article.created_at }}</p>
<p>수정일시 : {{ article.updated_at }}</p>
<br><br>
<a href="{% url 'articles:articles' %}">ArticlesPage로 돌아갈래요</a>
<br>
<hr>
{% if article.author == request.user %}
<a href="{% url 'articles:update' article.pk %}"><button>수정</button></a>
{% endif %}
<br>
{% if article.author == request.user %}
<form action="{% url 'articles:delete' article.pk %}" method="POST">
{% csrf_token %}
<input type="submit" value="글삭제">
</form>
{% endif %}
<hr>
<h3>댓글 {{ comments.count }}개</h3>
<form action="{% url 'articles:comment_create' article.pk %}" method="POST">
{% csrf_token %}
{{ comment_form.as_p }}
<input type="submit" value="댓글 작성">
</form>
{% for comment in comments %}
<p>{{ comment.content }}</p>
<p>작성자: {{ comment.author }}</p>
<p>작성일시: {{ comment.created_at }}</p>
{% if comment.author == request.user %}
<form action="{% url 'articles:comment_delete' comment.pk %}" method="POST">
{% csrf_token %}
<input type="submit" value="댓글 삭제">
</form>
{% endif %}
<hr>
{% empty %}
<p>댓글이 없습니다.</p>
{% endfor %}
{% endblock content %}
게시글 생성 시 작성자 저장
기본적으로 ModelForm은 모든 필드를 자동으로 저장하지만, author 필드는 request.user에서 가져와야 함
→ commit=False를 사용하여 수동으로 저장
from django.shortcuts import render, redirect
from .models import Article
from .forms import ArticleForm
def create_article(request):
if request.method == "POST":
form = ArticleForm(request.POST, request.FILES)
if form.is_valid():
article = form.save(commit=False) # DB 저장 전 인스턴스 생성
article.author = request.user # 작성자를 현재 로그인한 유저로 설정
article.save() # DB 저장
return redirect("articles:article_detail", article.pk)
else:
form = ArticleForm()
context = {"form": form}
return render(request, "articles/create.html", context)

- @login_required를 추가, 로그인하지 않은 사용자가 request.user로 접근할 때 AnonymousUser로 처리되는 문제 해결
게시글 수정 및 삭제 권한 설정
작성자만 게시글을 수정하거나 삭제할 수 있도록 조건 추가
from django.http import HttpResponseForbidden
def update_article(request, pk):
article = Article.objects.get(pk=pk)
if article.author != request.user: # 작성자가 아니면 수정 불가
return HttpResponseForbidden("이 게시글을 수정할 권한이 없습니다.")
if request.method == "POST":
form = ArticleForm(request.POST, instance=article)
if form.is_valid():
form.save()
return redirect("articles:article_detail", article.pk)
else:
form = ArticleForm(instance=article)
context = {"form": form}
return render(request, "articles/update.html", context)
articles/views.py
def delete_article(request, pk):
article = Article.objects.get(pk=pk)
if article.author != request.user: # 작성자가 아니면 삭제 불가
return HttpResponseForbidden("이 게시글을 삭제할 권한이 없습니다.")
article.delete()
return redirect("articles:article_list")




'∟ Framework > ⊢ Django' 카테고리의 다른 글
Django - Bootstrap, FontAwesome 활용 (1) | 2025.02.27 |
---|---|
Django - Model Relationship (M:N) (0) | 2025.02.24 |
Django - 1:N 관계 (Many-to-One Relationships) (1) | 2025.02.20 |
Django - Admin Site 활용 (1) | 2025.02.13 |
Django - Static & Media (2) | 2025.02.08 |