본문 바로가기
Research/Django

[django]MDSE_03_웹사이트에 로그인,로그아웃 기능 구현하기

by RIEM 2021. 11. 22.
728x90

개요

이 게시글은 장고 기반의 웹사이트를 구축하는 과정을 기록한 문서입니다. 장고 튜토리얼 ‘점프투파이썬(https://wikidocs.net/71303)’을 참조하여 작성했습니다.

목표

작성된 웹사이트에 로그인과 로그아웃을 할 수 있는 기능을 추가한다.



로그인과 로그아웃

장고에는 ‘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 앱

로그인, 로그아웃 기능은 웹사이트 전체에서 공통으로 사용할 수 있기 때문에 detection앱에 종속시키지 말고 새로운 ‘common’이라는 앱을 생성하여 로그인, 로그아웃 기능을 구현해보자.


App 생성

Common 앱 생성하기

C:\Users\yangs\Desktop\team6app>django-admin startapp common

 

폴더를 확인해보자.



> ../config/settings.py

config/settings.py 파일에 생성한 common 앱 등록해주자.

 
...

INSTALLED_APPS = [
  'common.apps.CommonConfig',
  'detection.apps.DetectionConfig',
  'django.contrib.admin',
  'django.contrib.auth',
  'django.contrib.contenttypes',
  'django.contrib.sessions',
  'django.contrib.messages',
  'django.contrib.staticfiles',
]

...


> ../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('detection/', include('detection.urls')),
  path('common/', include('common.urls')),
]

 

이제 localhost:8000/common/으로 시작하는 URL 모두 common/urls.py 파일을 참조하게 되었다. 이제 common/urls.py 파일을 생성해주자.


> ../common/urls.py

 
app_name = 'common'

urlpatterns = [
 
]

우선 앱 기능은 추가하지 않고 비워두자.

 

로그인

본격적으로 로그인 기능을 구현해보자. 

> templates/base.html

 
<div class="collapse navbar-collapse" id="ftco-nav">
      <ul class="navbar-nav ml-auto">
      <li class="nav-item active"><a href="/detection/" class="nav-link">Home</a></li>
      <li class="nav-item active"><a href="{% url 'common:login' %}" class="nav-link">Login</a></li>
      <li class="nav-item active"><a href="/detection/dataset" class="nav-link">Dataset</a></li>
      <li class="nav-item active"><a href="/detection/statistics" class="nav-link">Statistics</a></li>
      <li class="nav-item active"><a href="/detection/producer" class="nav-link">producer</a></li>
    </ul>
</div>
</div>
</nav>

 

전 사이트에 공통으로 사용하는 Base.html template의 상단 로그인 버튼을 common url과 매핑해주자

 

로그인 뷰

Base.html의 탬플릿 태그로 {% url ‘common:login’%}를 사용했으니, common/urls.py파일도 아래와 같이 수정해주자.

> 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='detection/login.html'), name='login'),
]

 

Template_name의 값은 디렉터리 주소이며, template/detection/login.html 경로를 의미한다.

> ../templates/detection/login.html

 
<div class="card">
  <div class="card-body">
    <div class="m-sm-4">

        <form method="post" class="post-form" action="{% url 'common:login' %}">
          {% csrf_token %}
          {% include "form_errors.html" %}

          <div class="mb-3">
              <label for="username" class="form-label">ID</label>
              <input class="form-control form-control-lg" type="text" name="username" id="username"
                    placeholder="Enter your name" value="{{ form.username.value|default_if_none:'' }}">
          </div>
          <div class="mb-3">
              <label for="password" class="form-label">Password</label>
              <input class="form-control form-control-lg" type="password" name="password" id="password"
                    placeholder="Enter password" value="{{ form.password.value|default_if_none:'' }}">
          </div>
          <div class="text-center mt-3">
              <button type="submit" class="btn-primary">Sign up</button>
          </div>
        </form>
    </div>
  </div>
</div>

 

Username과 password는 django.contrib.auth 앱에 필요한 필수항목이다. 로그인 실패 시 실패요인이 무엇인지 알려주는 form_error.html 템플릿 파일을 작성해주자.

> ../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 %}

 

폼 오류는  2가지로 필드 오류(field.errors)와 넌필드 오류(form.non_field_errors)가 있다. 필드 오류는 값이 누락되거나 필드 형식에 맞지않는 등 사용자의 입력값과 관련된 오류다. 넌필드 오류는 말 그대로 필드값과 무관하게 다른 요인으로 발생하는 오류라 보면 된다.

 

{자, 이제 화면으로 확인해보자. 비정상적인 아이디와 비밀번호를 입력하니 아래와 같은 오류창이 뜬다.


> ../config/settings.py

 
...

LOGIN_REDIRECT_URL = '/'

config/settings.py 파일에 위 코드를 추가해주자. 성공 시 기본 페이지인 ‘/’ 페이지로 이동하도록 해주기 때문이다. 현재는 django.contrib.auth 패키지가 디폴트로 /accounts/profile/ 이라는 URL로 이동시키는데 이로인해 오류가 발생할 것이다.


> ../config/urls.py

주소 ‘/’에 해당하는 URL을 매핑해주자.

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

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

 

로그아웃

로그인 기능을 구현했으니 로그아웃 기능도 적용해주자.

>../templates/base.html

 
<li class="nav-item active">
  {% if user.is_authenticated %}
  <a class="nav-link" href="{% url 'common:logout' %"} {{ user.username }} Logout </a>
  {% else %}
  <a class="nav-link" href="{% url 'common:login' %}" >Login</a>
  {% endif %}
</li>

 

{% if user.is_authenticated %}은 현재 사용자의 로그인 확인 여부 판별을 위함이다. 로그인이 된 경우 로그아웃 링크를 표시하고, 그렇지 않을 경우(else) 로그인 링크를 {{user.username}}과 함께 표시한다. 

 

로그아웃 링크 속성인 {% url ‘common:logout’%}에 대응하는 URL매핑을 common/urls.py파일에 추가해야 한다.

> ../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='detection/login.html'), name='login'),
  path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]
728x90

댓글