Django에서 기본적으로 제공해주는 로그인 관련 뷰와 템플릿은 매우 편하다. 대략적으론 다음과 같이 사용할 수 있다.

 

yourapp/urls.py

from django.contrib.auth import views as auth_view

urlpatterns = [
    path('login/',
    auth_view.LoginView.as_view(template_name='registration/login.html'), name='login')
    ]

 

templates/registration/login.html

        <div class="alert alert-info">로그인</div>
        <form action="" method="post">
            {% csrf_token %}
            {{form.as_p}}
            <input class="btn btn-primary" type="submit" value="Login">
        </form>

 

 

   그런데, 이 상태에선 기능적으로는 문제가 없지만, 사용자 경험면에서는 문제가 좀 있다.

 

  위의 코드로 만들어진 로그인 화면이고, 위의 Please ~ 문구는 비밀번호를 틀리면 나오는 문구이다.

나는 템플릿엔 어떠한 텍스트도 넣지 않았으니 아마 form에서 자체적으로 산출된 텍스트들일 것으로 추정할 수 있다.

 

  이 글을 보는 사람들은 거의 개발자일 것이니 이 정도 영어는 신경쓰이지 않을 수도 있겠지만,

일반 사용자들은 그렇지 않을 것이다. 그래서, 이 영어 범벅 폼을 개조해서 한글화를 해 보기로 했다.

오류 문구는 물론, Email과 Password 역시 내가 DB에 저장해 놓은 이름이 그대로 출력되고 있기 때문에 이 역시 바꿔보기로 했다.

 


 

  우선, LoginView부터 살펴보도록 하자. 파이참을 사용한다면 해당 클래스에 커서를 대고 Ctrl+B로 해당 클래스의 정의로 바로 넘어갈 수 있다.

 

  밑에 자잘한 함수들이 있으니 이 뷰가 어떻게 동작하는 지 관심이 있다면 읽어보자.

form_class = AuthenticationForm

에만 주목하면 해당 이름의 Form을 로그인에 활용하는 것으로 추정할 수 있고, 밑에서 get_form_class() 라는 함수를 통해 해당 form을 사용하도록 설정하는 코드가 있다.

  그러므로 우리가 수정해야 할 건 이 Form일 것이다.

 

 

 

  아래의 error_messages를 보면 위에서 봤던 익숙한 문구들이 보인다. 이제 이 부분을 전부 수정하면 될 것이다.

수정해야 할 부분을 찾았으니, 이제 코드로 작성해보자.

 

 

 

yourapp/forms.py

from django.contrib.auth.forms import AuthenticationForm

class CustomAuthenticationForm(AuthenticationForm):
    error_messages = {
        'invalid_login': (
            "비밀번호나 이메일이 올바르지 않습니다. 다시 확인해 주세요."
        ),
        'inactive': ("이 계정은 인증되지 않았습니다. 인증을 먼저 진행해 주세요."),
    }

 

 

에러 메세지들은 수정했으니, 이제 필드 이름을 수정할 차례이다. 해당 클래스의 __init__ 함수를 보자.

 

 

 유저네임 필드의 최대 길이와 라벨명 등을 설정하고 있다. 해당 부분을 오버라이딩 하면 될 것이다.

 

 

* 글쓴이는 username 대신 email을 쓰고 있는데? 

 

  맞다. 나는 User 클래스를 아예 새로 만들어서 쓰고 있다. 그래서 로그인에서 ID 없이 이메일과 비밀번호만으로 로그인을 하고 있고, username이라는 필드는 아예 모델에 없다. 그래도 지금까지 위 코드가 정상 작동 했다. 왜냐하면,

self.username_field = UserModel._meta.get_field(UserModel.USERNAME_FIELD)

이 부분 때문이다. 장고의 기본 User 모델에 username이라는 필드가 있고 해당 필드를 로그인시에 활용하는 건 맞다.

  일단, 이 Form에서의 username이라는 이름은 그냥 필드 이름 그 이상도 이하도 아니다.

두 이름이 겹치는 건 일단 그냥 우연이라고 생각하면 된다. 중요한 건, 이 Form에서의 username 필드를 정의할 때, Usermodel의 USERNAME_FIELD를 이용해 정의를 한다. 즉 로그인 인증에서 사용하는 유저 모델의 설정을 따라간다.

그리고 나는 커스터마이징한 유저 모델에서 USERNAME_FILED를 email이라고 정의해 두었기에, 맨 위의 로그인 창에서 Email이라고 표시된 것이다.

 


 

위의 관찰 내용을 이용하여 커스터마이징을 계속해 보자.

 

yourapp/forms.py

from django.contrib.auth.forms import AuthenticationForm

class CustomAuthenticationForm(AuthenticationForm):
    error_messages = {
        'invalid_login': (
            "비밀번호나 이메일이 올바르지 않습니다. 다시 확인해 주세요."
        ),
        'inactive': ("이 계정은 인증되지 않았습니다. 인증을 먼저 진행해 주세요."),
    }

    def __init__(self, request=None, *args, **kwargs):
        super(CustomAuthenticationForm, self).__init__(*args, **kwargs) # 꼭 있어야 한다!
        self.fields['username'].label = '이메일'
        self.fields['password'].label = '비밀번호'

 

 

  원한다면 길이 제한 등도 건들 수 있지만 여기서는 필요하지 않아서 따로 수정하지 않았다.

이대로 하기 전에, 다시 한번 원본 코드를 보고 이 부분을 주목해보자.

        if self.fields['username'].label is None:
            self.fields['username'].label = capfirst(self.username_field.verbose_name)

username 필드의 라벨이 지정되어 있지 않으면, 해당 username 필드의 verbose_name을 가져온다고 되어 있다.

그렇다면, 내가 커스터마이징했던 모델에서 verbose_name을 지정한다면 최소한 이메일 부분은 한글화가 되지 않을까?

 

 

class User(AbstractBaseUser):
    email = models.EmailField(
        verbose_name='이메일',
        max_length=255,
        unique=True,
    )
    
    USERNAME_FIELD = 'email'
    # ...

 

이렇게 지정하고, migration을 진행한다면...

 

 

  잘 적용 되었다. 이렇게 된다면 username 필드는 따로 건들 필요가 없게 되었다.

이런 식으로 매번 form class나 템플릿을 만지며 라벨을 일일이 달아 주는 건 비효율적일 것이다. 그래서 직접 form의 label을 수정하는 것보다, 가능하다면 위와 같이 verbose_name을 적용하는게 제일 좋다.

 

 

 

코드를 수정하자.

 

yourapp/forms.py

from django.contrib.auth.forms import AuthenticationForm

class CustomAuthenticationForm(AuthenticationForm):
    error_messages = {
        'invalid_login': (
            "비밀번호나 이메일이 올바르지 않습니다. 다시 확인해 주세요."
        ),
        'inactive': ("이 계정은 인증되지 않았습니다. 인증을 먼저 진행해 주세요."),
    }

    def __init__(self, request=None, *args, **kwargs):
        super(CustomAuthenticationForm, self).__init__(*args, **kwargs) # 꼭 있어야 한다!
        self.fields['password'].label = '비밀번호'

 

 

폼은 완성되었다. 이제 뷰를 수정하자.

 

yourapp/views.py

 

from django.contrib.auth import views as auth_view
from .forms import CustomAuthenticationForm

class CustomLoginView(auth_view.LoginView):
    form_class = CustomAuthenticationForm

 

Form까지 적용이 완료되었다. 이제 뷰를 교체하자.

 

 

yourapp/urls.py

 

from .views import CustomLoginView

urlpatterns = [
    path('login/',
    CustomLoginView.as_view(template_name='registration/login.html'), name='login')
    ]

 

 

이제 결과를 보자.

 

 

  모두 한글화가 되었다. 

맨 아래의 Login 버튼은 Form에 포함된 게 아니라 템플릿에 들어 있는 요소여서 바로 수정할 수 있을 것이다. 

 

 

  이외에도 커스터마이징 할 수 있는 요소가 많이 있다.

여기서 다루지 않은 속성이나 함수들도 적절히 오버라이딩 한다면 훨씬 많은 걸 할 수 있을 것이다.

 

+ Recent posts