Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

Nonamed Develog

[TIL][240819] Overriding 본문

WHAT I LEARN/TIL

[TIL][240819] Overriding

노네임드개발자 2024. 8. 19. 22:36
어떤 문제가 있었나?

프로젝트에서 사용자 정보 업데이트 및 비밀번호 변경 기능을 구현하다가 막히는 부분이 있었다. Django의 기본 제공 Form인 UserChangeForm과 PasswordChangeForm을 사용하면 되지만, 기본 동작을 커스텀할 필요가 있었었다. 회원정보수정 부분은 너무 많은 권한이 주어지기 때문에 수정할 부분을 지정해줘야 했고, 특히 비밀번호에 사용자에게 안내 텍스트를 추가하고 링크도 내가 원하는 경로로 설정해야 했다.


무엇을 시도했나?

  • CustomUserChangeForm 오버라이딩
    - Django 기본 UserChangeForm을 상속받아 사용자 정보 업데이트 기능을 커스텀했다. 비밀번호 필드의 도움말을 수정하여 사용자가 비밀번호 변경 페이지로 쉽게 이동할 수 이도록 링크를 추가하고 경로를 설정하였다.
    - __init__ 메서드를 오버라이딩하여 password 필드가 존재하는 경우, 동적으로 비밀번호 변경 페이지의 URL을 포함한 안내 택스트를 추가했다.
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserChangeForm
from django.urls import reverse

class CustomUserChangeForm(UserChangeForm):
    class Meta:
        model = get_user_model()  # 현재 프로젝트에서 사용하는 사용자 모델을 가져옴
        fields = ("username", "email", "first_name", "last_name")  
        # 사용자 정보 수정에서 사용할 필드를 정의

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)  
        # 부모 클래스의 __init__ 메서드를 호출하여 폼을 초기화
        # 'password' 필드가 존재하면, 비밀번호 변경 안내 링크 추가
        if self.fields.get("password"):
            password_help_text = (
                "You can change the password " '<a href="{}">here</a>.'  
                # 비밀번호 필드의 도움말 텍스트를 수정, 비밀번호 변경 페이지로 이동할 수 있는 링크를 추가
            ).format(reverse('accounts:change_password'))  
            # 'accounts:change_password'라는 이름의 URL을 동적으로 생성하여 링크를 삽입
            self.fields["password"].help_text = password_help_text 
            # 수정된 도움말을 'password' 필드에 적용

- CustomUserChangeForm은 Django의 UserChangeForm을 상속받아 사용자 정보를 수정하는 폼이다.

- Meta 클래스를 통해 수정 가능한 필드를 username, email, first_name, last_name으로 설정했다.

- __init__ 메서드를 오버라이딩하여 password 필드가 존재할 경우, 비밀번호 변경 페이지로 이동할 수 있는 링크를 추가하여 사용자 편의성을 높였다. 링크는 reverse 함수를 통해 URL namespace에 동적으로 가져와 설정했다.

 

  • CustomUserChangeForm을 사용하는 update view
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from django.views.decorators.http import require_http_methods
from .forms import CustomUserChangeForm

@require_http_methods(["GET", "POST"])  # 이 뷰는 GET 및 POST 요청만 허용
@login_required  # 로그인이 필요한 뷰로 설정
def update(request):
    if request.method == "POST":  # POST 요청일 경우, 폼에서 전달된 데이터로 사용자 정보를 업데이트합
        form = CustomUserChangeForm(request.POST, instance=request.user)  
        # 현재 로그인된 사용자를 instance로 전달하여 폼을 초기화
        if form.is_valid():  # 폼 유효성 검사를 통과하면
            form.save()  # 사용자의 정보를 저장
            return redirect("index")  # 정보 수정 후, index 페이지로 리디렉션
    else:  # GET 요청일 경우, 사용자 정보를 폼에 미리 채워서 표시
        form = CustomUserChangeForm(instance=request.user)  
        # 현재 로그인된 사용자의 정보를 instance로 전달하여 폼을 초기화
    context = {"form": form}  # 컨텍스트로 폼을 템플릿에 전달
    return render(request, "accounts/update.html", context)  
    # accounts/update.html 템플릿을 렌더링하여 사용자에게 보여줌

- update view는 사용자가 자신의 정보를 업데이트할 수 있는 페이지를 처리한다.

- POST 요청 시 CustomChangeForm을 사용하여 제출된 데이터를 바탕으로 현재 사용자의 정보를 업데이트하고, index 페이지로 리디렉션 한다.

- GET 요청 시 CustomChangeForm을 사용하여 현재 사용자의 정보를 폼에 미리 채워 사용자에게 보여준다.

- login_required 데코레이터를 사용하여 로그인한 사용자만 이 뷰에 접근할 수 있다.

- require_http_methods 데코레이터를 사용해 이 뷰는 GET, POST 요청만 허용한다.

 

  • 비밀번호 기능 구현
    - 비밀번호 변경은 Django 기본 제공 PasswordChangeForm을 사용하지만 사용자가 비밀번호를 성공적으로 변경한 후에도 로그아웃되지 않도록 update_session_auth_hash를 사용하여 현재 세션을 유지했다.
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.forms import PasswordChangeForm
from django.shortcuts import render, redirect

def change_password(request):
    if request.method == "POST":  # POST 요청일 경우, 비밀번호 변경 작업을 수행
        form = PasswordChangeForm(request.user, request.POST)  # 현재 사용자의 비밀번호 변경 폼을 생성
        if form.is_valid():  # 폼 유효성 검사를 통과하면
            form.save()  # 사용자의 비밀번호를 저장합
            # 비밀번호 변경 후에도 세션을 유지
            update_session_auth_hash(request, form.user)  
            # 세션의 인증 정보를 갱신하여 로그아웃되지 않도록 처리
            return redirect("index")  # 비밀번호 변경 후, index 페이지로 리디렉션
    else:  # GET 요청일 경우, 비밀번호 변경 폼을 사용자에게 표시
        form = PasswordChangeForm(request.user)  # 현재 사용자의 비밀번호 변경 폼을 생성
    context = {"form": form}  # 컨텍스트로 폼을 템플릿에 전달
    return render(request, "accounts/change_password.html", context)  
    # accounts/change_password.html 템플릿을 렌더링하여 사용자에게 보여줌

- change_password 뷰는 사용자가 자신의 비밀번호를 변경할 수 있는 페이지를 처리한다.

- POST 요청 시 PasswordChangeForm을 사용하여 제출된 데이터를 바탕으로 비밀번호를 변경하고, update_sessioin_auth_hash를 호출하여 비밀번호 변경 후에도 사용자가 로그아웃되지 않도록 처리한다.

- GET 요청  시 PasswordChangeForm을 사용하여 비밀번호 변경 폼을 사용자에게 표시한다.

비밀번호 변경이 성공적으로 이뤄지면 index 페이지로 리디렉션 한다.


어떻게 해결됐는가?
  1. CustomUserChangeFrom 오버라이딩
    - CustomUserChangeForm에서 비밀번호 필드의 도움말을 커스텀하고 사용자에게 직관적인 안내를 할 수 있었다. 비밀번호 변경 안내 링크를 통해 사용자가 비밀번호 변경 페이지로 쉽게 이동할 수 있게 구현했다. 또한 내가 원하는 경로로 설정하였다.
  2. 비밀번호 변경 후 세션 유지
    - PaawordChangeForm을 이용해 비밀번호 변경 기능도 구현했다. update_session_auth_hash 함수를 사용하여 비밀번호 변경 후에도 사용자가 로그아웃되지 않도록 세션이 유지되게 처리했다.

새로 알게 된 점은 무엇인가?
  • CustomUserChangeForm 오버라이딩
    - Django의 기본 폼을 상속받아 필요에 맞게 오버라이딩함으로써 더 나은 사용자 경험을 할 수 있다는 것을 알았다. 특히 __init__ 메서드를 통해 동적으로 폼 필드를 수정하거나 추가적인 텍스트 삽입하는 방법에 대해 알게 되었다.
  • Update_session_auth_hash 함수의 역할
    - Update_session_auth_hash는 비밀번호 변경 후에도 사용자의 세션을 무효화하지 않고 유지시키는 중요한 함수다. 이 함수를 사용하기 전에는 비밀번호 변경 시 사용자는 로그아웃되며, 다시 로그인해야 하는 불편함이 생긴다. 아래와 같은 코드로 import 가능하다.
from django.contrib.auth import update_session_auth_hash

무엇을 느꼈고 내일은 무엇을 할까?

강의를 다 듣고 프로젝트를 시작했다. 스켈레톤 코드(프로젝트 생성-회원 CRUD 로직 구현)를 3:1 페어 코딩으로 팀원들과 작성하면서, 강의 때 배웠던 것들을 리마인드 하였고, 오버라이딩 같이 이해가 모자란 부분은 팀원들과 소통하며 풀어나갔다. 내일 스켈레톤 코드를 마저 작성하고, 다른 팀원과 1:1로 페어 코딩을 하게 되는데 누가 되지 않도록 예습을 해야겠다.