∟ Framework/⊢ Django

Django - Custom User Model

최 수빈 2025. 2. 24. 05:55

 

 

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
    )

accounts/models.py

  • groups와 user_permissions 필드에서 related_name을 변경하지 않으면 Django 기본 User 모델과 충돌이 발생할 수 있음

 

 

settings.py 사용자 모델 설정

 

Django 프로젝트에서 기본 사용자 모델을 교체하려면 AUTH_USER_MODEL 설정을 추가해야 함

# settings.py
...
AUTH_USER_MODEL = 'accounts.User'
...

→ Django는 accounts.User 모델을 기본 User 모델로 인식

settings.py

 

 

관리자 페이지에 Custom User Model 등록

 

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

accounts/admin.py

 

 

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 + ("추가필드",)  # 필요한 필드를 추가할 수 있음

accounts/forms.py

 

회원가입 view의 Form 변경

accounts/views.py

 

 

 

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"
    )

 

articles/models.py

 

각 게시글이 특정 사용자와 연결되며, 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)

articles/views.py

  • @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")

 

 

 

 

BiBiPRINCESS가 작성한 글, BiBiPRINCESS계정으로 본 화면과 admin계정으로 본 화면

'∟ 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