Django 점프 투 장고 정리
작성일 : 2021-11-16
문서버전 : 1.0
개요
이 문서는 점프 투 장고 사이트의 장고 튜토리얼 학습 내용을 정리한 내용입니다.
레퍼런스
점프 투 장고 https://wikidocs.net/72242
3-05. 로그인과 로그아웃
로그인과 로그아웃 기능을 추가해보자. 질문자와 답변자를 구분할 수 있게 해줄 것이다. 장고에서 로그인과 로그아웃을 도와주는 앱은 ‘django.contrib.auth’이다. 프로젝트 생성시에 아래와 같이 자동으로 생성된다.
> ../projects/mysite/config/settings.py
...
INSTALLED_APPS = [
'pybo.apps.PyboConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
...
Common 앱
로그인, 로그아웃 기능은 웹 사이트 전체에서 공통적으로 사용할 수 있다. 따라서 pybo 앱 내 종속시킬 필요는 없다. 이를 위해 사이트 전체의 공통 기능을 가진 앱이라는 의미의 ‘common’앱을 만들어서 로그인, 로그아웃 기능을 구현해보자.
> app 생성
아래 명령어로 common 앱을 생성시켜 주자.
(mysite)../projects/mysite/django-admin startapp common |
> ../projects/mysite/config/settings.py
config/settings.py 파일에 생성한 common 앱을 등록하기
INSTALLED_APPS = [
'common.apps.CommonConfig',
'pybo.apps.PyboConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
> ../projects/mysite/config/urls.py
Common 앱의 urls.py 파일 사용하기 위해선 config/urls.py 파일도 수정해야 한다
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('pybo/', include('pybo.urls')),
path('common/', include('common.urls')),
]
localhost:8000/common/으로 시작하는 URL은 모두 common.urls.py 파일을 참조하라고 패턴을 지정해주었다. 그럼 common.urls.py 파일을 생성해주자.
> ../projects/mysite/common/urls.py
app_name = 'common'
urlpatterns = [
]
앱에 기능은 추가하지 않았으니 빈 상태로 두자.
로그인
본격적으로 로그인 기능을 구현해보자. 로그인의 시작은 로그인 화면이다. 로그인 화면으로 들어갈 수 있도록 아래 파일의 로그인 링크를 아래와 같이 수정하자.
> ../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매핑을 추가해줘야 한다.
> ../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를 사용할 수 있다.
로그인 템플릿
위까지 수정하고 네비게이션바의 ‘로그인’링크를 누르면 아래와 같은 페이지가 뜬다. 주소는 localhost:8000/common/login/
오류는 registration 디렉터리에 login.html 파일이 없다는 뜻이다. 이는 앞서 사용한 LoginView는 ‘registration’템플릿 디렉터리에서 login.html 파일을 찾는데 해당 파일을 찾지 못했기 때문에 발생한 오류다. 이를 해결하기 위해 registration/login.html 템플릿 파일을 작성해야 한다.
로그인은 common 앱에 구현할 것이므로 오류 메시지의 안내 문구와 같이 registration 디렉터리에 템플릿 파일을 생성하기 보다는 common 디렉터리에 템플릿을 생성하는 것이 좋다.
> ../projects/mysite/common/urls.py
이를 위해 LoginView가 common 디렉터리의 템플릿을 참조할 수 있도록 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 파일을 참조하게 된다. 코드 수정 후 로그인 링크 누르면 여전히 오류 메시지나 난다. 그런데 오류 메시지가 조금 달라진 것을 알 수 있다.
registration/login.html이 아닌 common/login.html이 없다는 오류로 변경되었다. 그렇다면 common/login.html 파일 생성을 위해 common 템플릿 디렉터리를 다음과 같이 생성하자.
(mysite) c:\projects\mysite>cd templates (mysite) c:\projects\mysite\templates>mkdir common |
> ../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와 비밀번호를 입력받아 로그인하게 도와준다. Username과 password 항목은 django.contrib.auth 앱이 요구하는 필수항목이다.
그리고 {% csrf_token %} 밑에 include 태그로 포함된 form_error.html 템플릿 파일을 작성해주자.
> ../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 %}
일반적으로 폼 오류는 두 가지 종류가 있는데, 1) 필드 오류(field.errors)와 넌필드 오류(form.non_field_errors)다.
필드 오류(field.errors)는 사용자가 입력한 필드 값에 대한 오류를 지칭하는데, 값이 누락되거나 필드 형식이 일치하지 않는 경우 발생한다. 넌필드 오류(form.non_field_errors)는 필드값과 무관하게 다른 이유로 발생하는 오류다.
로그인 수행
네비게이션바의 로그인 링크 클릭하면 다음과 같은 화면을 볼 수 있다.
오류메시지도 정상적으로 뜬다.
지금은 슈퍼유저로 만든 ‘admin’계정만 로그인할 수 있다. 사용자 ID에 admin 입력 후 비밀번호에 1111을 입력해서 로그인을 수행해보자.
오류가 발생한 이유는 로그인 성공 시 django.contrib.auth 패키지는 디폴트로 /accounts/profile/라는 URL로 이동시키기 때문이다.
다만 /accounts/profile/ URL은 현재 우리가 파이보에 구성한 것과 맞지 않기 때문에 성공 시 ‘/’페이지로 이동할 수 있도록 config/settings.py 파일을 수정하자. 마지막 로그인줄에 LOGIN_REDIRECT_URL을 추가하면 된다. 여기서 ‘/’페이지는 기본 URL인 ‘http://localhost:8000/’ 페이지를 의미한다.
> ../projects/mysite/config/settings.py
(... 생략 ...)
# 로그인 성공후 이동하는 URL
LOGIN_REDIRECT_URL = '/'
그런데 localhost:8000 페이지로 접속하면 아래와 같은 오류가 발생한다.
이는 ‘/’를 의미하는 http://localhost:8000/ 페이지에 대한 URL 매핑을 하지 않았기 때문이다.
> ../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 함수가 실행된다.
로그아웃
로그인 성공 후, 네비게이션에서 로그인 링크를 로그아웃 링크로 바꾸기 위해서 navbar.html 템플릿 파일에서 로그인 링크 부분을 아래와 같이 수정한다.
> ../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 %} 은 현재 사용자가 로그인 되었는지 판별한다. 로그인 된 경우 로그아웃 링크를 추가하고, 그렇지 않은 경우(else) 로그인 링크를 표시한다. 로그인 상태일 경우 {{ user.username }}도 추가로 표시했다. 로그아웃 링크가 추가되었으므로 {% url ‘common:logout’ %}에 대응하는 URL 매핑을 common/urls.py 파일에 추가해야한다.
> ../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'),
]
Admin 계정(superman)으로 로그인 성공!
> ../projects/mysite/config/settings.py
로그아웃 이후 redirect할 위치도 추가해주자.
(... 생략 ...)
# 로그인 성공후 이동하는 URL
LOGIN_REDIRECT_URL = '/'
# 로그아웃시 이동하는 URL
LOGOUT_REDIRECT_URL = '/'
로그아웃하니 로그인 화면으로 정상적으로 redirect 되었다.
'Research > Django' 카테고리의 다른 글
[django]MDSE_01_웹사이트 간단한 문구 표시 (0) | 2021.11.22 |
---|---|
[Django] 점프 투 장고 튜토리얼 - 03-6. 계정생성 (0) | 2021.11.19 |
[Django] 점프 투 장고 튜토리얼 - 03-4. 답변 개수 표시 (0) | 2021.11.16 |
[Django] 점프 투 장고 튜토리얼 - 03-3. 템플릿 필터 (0) | 2021.11.16 |
[Django] 점프 투 장고 튜토리얼 - 03-2. 페이징(Paging) (0) | 2021.11.16 |
댓글