본문 바로가기

Django/Django 기초

[Django] 3 - 5. 로그인과 로그아웃

이전포스트

 

[Django] 1. 개발 환경 설정 https://wroni.tistory.com/4

[Django] 2 - 1. URL과 View https://wroni.tistory.com/5

[Django] 2 - 2. 모델 https://wroni.tistory.com/6

[Django] 2 - 3. 장고 관리자 https://wroni.tistory.com/7

[Django] 2 - 4. 조회와 템플릿 https://wroni.tistory.com/8

[Django] 2 - 5. URL과 네임스페이스, 2 - 6. 데이터 저장 https://wroni.tistory.com/9

[Django] 2 - 7. 스태틱 https://wroni.tistory.com/10

[Django] 2 - 8. 부트스트랩 https://wroni.tistory.com/11

[Django] 2 - 9. 템플릿 상속 https://wroni.tistory.com/12

[Django] 2 - 10. 폼 https://wroni.tistory.com/13

[Django] 3 - 1. 네비게이션바 https://wroni.tistory.com/14

[Django] 3 - 2. 페이징 https://wroni.tistory.com/15

[Django] 3 - 3. 템플릿 필터, 3 - 4. 답변 개수 표시 https://wroni.tistory.com/16


 

3 - 5. 로그인과 로그아웃

 

현재까지 로그인과 로그아웃 기능은 구현하지 않았다.

장고의 로그인, 로그아웃을 도와주는 앱은 django.contrib.auth이다. 이 앱은 장고 프로젝트 생성시 다음처럼 자동 추가 된다.

 

파일 : C:\projects\mysite\config\settings.py

INSTALLED_APPS = [
    (...생략...)
    'django.contrib.auth',
	(...생략...)
]

 

 

1. common 앱

 

하나의 웹 사이트에는 파이보와 같은 게시판 서비스 외에도 블로그나 쇼핑몰 같은 굵직한 단위의 앱들이 함께 있을 수 있기 때문에 공통으로 사용되는 기능인 로그인이나 로그아웃을 이 중의 하나의 앱에 종속시키는 것은 좋지 않다.

그렇기 때문에 여기서는 로그인 로그아웃을 공통 기능을 가진 앱이라는 의미의 common 앱에 구현할 것이다.

 

먼저 common 앱을 생성하자

 

 

디렉터리를 보면 pybo 앱과 동일한 구조의 디렉터리와 파일들이 자동으로 생성된다.

 

 

그리고 config/settings.py 파일에 생성한 common 앱을 등록하자.

 

파일 : C:\projects\mysite\config\settings.py

'common.apps.CommonConfig',  # 내용을 추가

 

이어서 common 앱의 urls.py 파일을 사용하기 위해 config/urls.py 파일을 다음과 같이 수정할 것이다.

 

파일 : C:\projects]mysite\config\urls.py

path('common/', include('common.urls')), # 내용 추가

 

이제 http://localhost:8000/common/ 으로 시작하는 URL은 모두 common/urls.py 파일을 참조할 것이다.

 

그리고 common/urls.py 파일을 신규로 작성한다.

 

파일 : C:\projcets\mysite\common\urls.py

app_name = 'common'

urlpatterns = [
]

 

아직 common 앱에 어떤 기능도 구현되지 않았기 때문에 urlpatterns는 빈 상태로 둔다.

 

 

2. 로그인

 

로그인 시작은 로그인 화면이다. 로그인 화면에 진입할 수 있도록 templates/navbar.html 파일의 '로그인' 링크를 수정한다.

 

파일 : C:\projects\mysite\templates\navbar.html

(...생략...)
<ul class="navbar-nav">
    <li class="nav-item ">
        <a class="nav-link" href="{% url 'common:login' %}">로그인</a>
    <li>
</ul>
(...생략...)

 

navbar.html 파일에서 템플릿 태그로 {% url 'common:login' %} 를 사용했으므로 common/urls.py 파일에 URL 매핑을 추가해야 한다.

 

파일 : C:\projects\mysite\common\urls.py

from django.urls import path
from django.contrib.auth import views as auth_views

app_name = 'common'

urlpatterns = [
    path('login/', auth_views.LoginView.as_view(), name='login'),
]

 

로그인 뷰는 따로 만들 필요 없이 위의 코드처럼 django.contrib.auth 앱의 LoginView를 사용한다.

 

 

브라우저에서 네비게이션바의 '로그인'링크를 누르면 다음과 같은 오류페이지가 나타난다.

 

 

registration 디렉터리에 login.html이 없다고 뜬다. LoginView는 registration이라는 템플릿 디렉터리에서 login.html 파일을 찾는다.

지금은 이 파일을 찾지 못해서 오류가 발생하였다. 이 오류를 해결하려면 registration/login.html 템플릿 파일을 작성해야 한다.

 

하지만, 로그인 common 앱에 구현할 것이므로 오류 메세지에 나온 것처럼 registration 디렉터리에 파일을 생성하는 것이 아니고

common 디렉터리에 템플릿을 생성할 것이다. 이를 위해 LoginView가 common 디렉터리의 템플릿을 참조하도록 common/urls.py 파일을 수정하자.

 

파일 : C:\projects\mysite\common\urls.py

from django.urls import path
from django.contrib.auth import views as auth_views

app_name = 'common'

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

 

수정하면 이제 registration 디렉터리가 아니라 common 디렉터리에서 login.html 파일을 참조하게 된다.

코드 수정 후 로그인 링크를 눌러보면, 여전히 오류 메세지가 나타나고 있다.

 

 

이번엔 common/login.html이 없다는 오류가 뜨고 있다.

 

common/login.html 파일 생성을 위해 common 템플릿 디렉터리를 생성하자.

 

cd templates

mkdir common

 

이제 common 템플릿 디렉터리에 login.html 템플릿을 작성할 것이다.

 

파일 : C:\projects\mysite\templates\common\login.html

{% extends "base.html" %}
{% block content %}
<div class="container my-3">
    <form method="post" class="post-form" action="{% url 'common:login' %}">
        {% csrf_token %}
        {% include "form_errors.html" %}
        <div class="form-group">
            <label for="username">사용자ID</label>
            <input type="text" class="form-control" name="username" id="username"
                   value="{{ form.username.value|default_if_none:'' }}">
        </div>
        <div class="form-group">
            <label for="password">비밀번호</label>
            <input type="password" class="form-control" name="password" id="password"
                value="{{ form.password.value|default_if_none:'' }}">
        </div>
        <button type="submit" class="btn btn-primary">로그인</button>
    </form>
</div>
{% endblock %}

 

사용자ID와 비밀번호를 입력받아서 로그인하는 템플릿이다. 로그인에 사용되는 사용자ID는 username을 의미, 비밀번호를 의미하는 password는 django.contrib.auth 앱이 요구하는 필수항목이다.

 

그리고 {% csrf_token %} 바로 밑에 include 태그로 포함된 form_error.html 템플릿 파일을 다음과 같이 작성하자.

 

파일 : C:\projects\mysite\templates\form_errors.html

{% if form.errors %}
    {% for field in form %}
        {% for error in field.errors %}    <!-- 필드 오류 출력 -->
            <div class="alert alert-danger">
                <strong>{{ field.label }}</strong>
                {{ error }}
            </div>
        {% endfor %}
    {% endfor %}
    {% for error in form.non_field_errors %}    <!--넌필드 오류를 출력한다. -->
        <div class="alert alert-danger">
            <strong>{{ error }}</strong>
        </div>
    {% endfor %}
{% endif %}

 

form_errors.html 템플릿은 로그인 실패시 로그인이 왜 실패하였는지 알려주는 역할을 하고 있다.

 

폼 오류에는 다음과 같이 두 종류의 오류가 있다.

 

- 필드 오류(field.errors)

- 넌필드 오류(form.non_field_errors)

 

필드 오류는 사용자가 입력한 필드 값에 대한 오류로 값이 누락되었거나 필드의 형식이 일치하지 않는 경우에 발생하는 오류이다.

넌필드 오류는 필드의 값과는 상관없이 다른 이유로 발생하는 오류이다.

form_errors.html 템플릿은 필드 오류와 넌필드 오류 모두를 표시하기 위해 삽입되는 템플릿이다.

 

 

3. 로그인 수행

 

네비게이션바의 로그인 링크를 클릭하면 다음과 같이 로그인 창이 뜬다.

 

 

현재 로그인 가능한 슈퍼유저 "admin"으로 로그인을 수행해보자.

 

사용자 ID에 admin 입력하고 비밀번호에 1111 입력하여 로그인 해보자.

 

다음과 같이 오류가 발생한다.

 

 

로그인이 성공하면 django.contrib.auth 패키지는 디폴트로 /account/profile/ 라는 URL로 이동시킨다

 

그런데, /account/profile/ URL은 현재 파이보에 구성한 것과 맞지 않기 때문에 로그인 성공시 / 페이지로 이동하도록

config/settings.py 파일을 수정하자. 마지막 줄에 LOGIN_REDIRECT_URL을 추가하면 된다.

 

/ 페이지는 http://localhost:8000/ 페이지를 의미한다.

 

파일 : C:\projects\mysite\config\settings.py

(...생략...)
# 로그인 성공후 이동하는 URL
LOGIN_REDIRECT_URL = '/'

 

이렇게 수정하고 config/urls.py 파일에 / 페이지에 대응하는 URL 매핑을 추가하자.

 

파일 : C:\projects\mysite\config\urls.py

from django.contrib import admin
from django.urls import path, include
from pybo import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('pybo/', include('pybo.urls')),
    path('common/', include('common.urls')),
    path('', views.index, name='index'), #'/'에 해당되는 path
]

 

이렇게 수정하면 / 페이지 요청에 대해서 path('', views.index, name='index')가 작동하여 pybo/views.py 파일의 index 함수가 실행된다. 여기까지 수정한 다음 로그인이 잘 되는지 확인해보면

 

 

슈퍼유저로 로그인이 성공되었다.

 

 

4. 로그아웃

 

로그인에 성공한 후에는 "로그아웃" 링크로 바뀌도록 해야 한다.

 

navbar.html 템플릿 파일에서 로그인 링크 부분을 다음과 같이 수정하자.

 

파일 : C:\projects\mysite\templates\navbar.html

(...생략...)
            <li class="nav-item ">
                {% if user.is_authenticated %}
                <a class="nav-link" href="{% url 'common:logout' %}">{{ user.username }} (로그아웃)</a>
                {% else %}
                <a class="nav-link" href="{% url 'common:login' %}">로그인</a>
                {% endif %}
            </li>
(...생략...)

 

{% if user.is_authenticated %} 는 현재 사용자가 로그인이 되어있는지를 판별하는 것이다.

따라서 로그인이 되어 있다면, "로그아웃" 링크를 표시하고, 로그인이 되어 있지 않다면 로그인을 표시하도록 하였다.

 

로그아웃 링크가 추가되었으니 {% url 'common:logout' %} 에 대응하는 URL 매핑을 common/urls.py 파일에 추가하자.

 

파일 : C:\projects\mysite\common\urls.py

from django.urls import path
from django.contrib.auth import views as auth_views

app_name = 'common'

urlpatterns = [
    path('login/', auth_views.LoginView.as_view(template_name='common/login.html'), name='login'),
    path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]

 

로그아웃 코드를 추가시켜준다. 이제 슈퍼유저로 로그인하면 로그인 링크가 다음과 같이 변경된다.

 

 

그리고 로그아웃 하고 리다이렉트 할 위치도 config/settings.py 파일에 추가해야 한다.

 

파일 : C:\projects\mysite\config\settings.py

# 로그아웃시 이동하는 URL
LOGOUT_REDIRECT_URL = '/'

 

로그아웃 하고 / 페이지로 이동하기 위해 LOGOUT_REDIRECT_URL을 설정하였다.

 

코드 수정 후 로그인, 로그아웃을 둘다 수행하면 잘 작동하고 있다.

 


※ 본 내용은 django 공부 기록이며, 점프 투 장고를 참고하였습니다.

https://wikidocs.net/book/4223

 

점프 투 장고

**점프 투 장고 오프라인 책 출간 !! (2020.12)** * [책 구입 안내](https://wikidocs.net/105844)

wikidocs.net