본문 바로가기

Back-end/Forum with Django

31. 회원 탈퇴

서버 측 작업

회원탈퇴 뷰는 구현이 간단하기 때문에 auth_view에 작성되어 있지 않습니다. 직접 구현해 봅시다.

member/models.py

먼저 회원 탈퇴 시 이유를 묻고 그 데이터를 저장하는 모델을 생성해 봅시다.

from django.contrib.auth.models import AbstractUser
from django.db import models


class ForumUser(AbstractUser):
    nickname = models.CharField(max_length=10)


# 아래처럼 각 필드를 생성하거나 하나의 charField에 ','join 연산을 통해 통째로 집어 넣어도 됩니다.
# 다만 DB 쿼리 요청 만으로 간편하게 데이터를 확인할 수 있도록 각자의 필드를 생성하였습니다.
class DeleteReason(models.Model):
    not_use = models.BooleanField(default=False)
    lack_of_features = models.BooleanField(default=False)
    poor_management = models.BooleanField(default=False)
    other_detail = models.CharField(max_length=100, blank=True, null=True)

마이그레이션을 진행해 줍니다.

(.venv) C:\Users\***\PycharmProjects\forum-with-django>python manage.py makemigrations
Migrations for 'member':
  member\migrations\0002_deletereason.py
    + Create model DeleteReason

(.venv) C:\Users\***\PycharmProjects\forum-with-django>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, forum, member, sessions
Running migrations:
  Applying member.0002_deletereason... OK

member/forms.py

뷰와 템플릿에서 모델을 편하게 사용하기 위해 장고 폼을 생성합니다.

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.hashers import check_password

from member.models import ForumUser, DeleteReason


class RegisterForm(UserCreationForm):
    ...


class DeleteReasonForm(forms.ModelForm):
    password = forms.CharField(label="비밀번호 확인", widget=forms.PasswordInput)
    class Meta:
        model = DeleteReason
        fields = ['not_use', 'lack_of_features', 'poor_management', 'other_detail']
        labels = {
            'not_use': '더이상 사용하지 않음',
            'lack_of_features': '기능의 부재',
            'poor_management': '운영상 미숙',
            'other_detail': '기타(입력해 주세요.)'
        }

    # 비밀번호 확인을 위해 __init__과 clean메서드를 생성합니다.
    # 만약 비밀번호 확인 기능이 없다면 추가하지 않아도 됩니다.
    # __init__과 super()에 대한 설명은 다음차시에서 진행합니다.
    def __init__(self, user, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.user = user

    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get('password')
        if password and not check_password(password, self.user.password):
            self.add_error('password', '비밀번호가 일치하지 않습니다.')

member/urls.py

urlpatterns = [
    ...
    # 탈퇴 후 사용자에게 확인 메세지를 보여주기 위해 /done/ 엔드포인트를 작성하였습니다.
    path('delete/',                views.delete,                    name='delete'),
    path('delete/done/',           views.delete_done,               name='delete_done'),
    ...

member/views.py

@login_required
def delete(request):
    if request.method == 'GET':
        form = DeleteReasonForm(request.user)
        return render(request, 'registration/membership_delete_form.html', {'form': form})
    elif request.method == 'POST':
        # 매개변수 순서에 주의
        form = DeleteReasonForm(request.user, request.POST)
        if form.is_valid():
            form.save()
            request.user.delete()
            logout(request)
            return redirect('member:delete_done')
        else:
            return render(request, 'registration/membership_delete_form.html', {'form': form})


def delete_done(request):
    return render(request, 'registration/membership_delete_done.html')

클라이언트 측 작업

profile.html

로그인한 사용자의 프로필 페이지라면 회원탈퇴 버튼을 출력합니다.

{% extends 'base.html' %}
{% block title %}
{{ profile_user.nickname }}'s Profile
{% endblock title %}

{% block body %}
<div class="container mt-3">
    <div class="card">
        ...
        {% if request.user == profile_user %}
        <div class="card-footer">
            <a href="{% url 'member:delete' %}" class="btn btn-danger float-right" type="button">회원 탈퇴</a>
        </div>
        {% endif %}
    </div>
</div>
{% endblock body %}

membership_delete_form.html

{% extends 'base.html' %}
{% block title %}
Delete Membership
{% endblock %}
{% block style %}
{% endblock %}

{% block body %}
    <div class="container">
        <form method="POST">
            {% csrf_token %}
            <h2>회원 탈퇴</h2>
            <!-- 템플릿에서 장고 폼을 사용하여 p태그로 감싸 checkbox 생성 -->
            {{ form.as_p }}
            <button type="submit" class="btn btn-danger">Delete</button>
        </form>
    </div>
{% endblock %}

membership_delete_done.html

{% extends 'base.html' %}
{% block title %}
Delete Membership Done
{% endblock %}

{% block body %}
    <div class="container">
        <h4>회원 탈퇴 완료</h4>
        <p>이용해 주셔서 감사합니다.</p>
    </div>
{% endblock %}

결과 확인

'Back-end > Forum with Django' 카테고리의 다른 글

33. 조회수  (1) 2025.09.08
32. __init__과 super()  (3) 2025.08.12
30. 프로필 페이지  (2) 2025.08.12
29. 비밀번호 변경  (0) 2025.08.12
28. SMTP, django-environ  (2) 2025.07.29