Login.html

만들어볼 login.html의 모습. 참고로 template을 손보기 이전 모습은 여기 페이지에서 볼 수 있다. 아래처럼 디자인하려면 bootstrap을 이용한다.


Django Login Page





프로젝트 폴더의 urls.py

※ 참고 : Django 공식문서


프로젝트 폴더의 urls.py의 urlpatterns에 accounts의 url 경로를 추가한다.


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

urlpatterns = [
    # 추가하지 않으면 login 페이지에 접근할 수 없다.
    path('accounts/', include('django.contrib.auth.urls')),  
    ...(생략)...
]


Django accounts 템플릿

auth.urls를 include하면 다음과 같은 url들이 포함된다. 목록에 있는 것들을 원하는 대로 쓸 수 있다. 이 포스팅에서는 login, logout을 활용한다.

accounts/login/ [name='login']
accounts/logout/ [name='logout']
accounts/password_change/ [name='password_change']
accounts/password_change/done/ [name='password_change_done']
accounts/password_reset/ [name='password_reset']
accounts/password_reset/done/ [name='password_reset_done']
accounts/reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/reset/done/ [name='password_reset_complete']





앱 폴더의 urls.py


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

urlpatterns = [
    path('login/', auth_views.LoginView.as_view(), name="login"),
    path('logout/', auth_views.LogoutView.as_view(), name="logout"),
    ...(생략)...
]


from django.contrib.auth import views as auth_views를 추가해야 Django auth에 내장되어 있는 LoginView, LogoutView를 사용할 수 있다. 따라서 앱 폴더의 views.py에서 따로 코드를 작성할 필요가 없다.

as auth_views로 alias(별칭)을 주는 이유는 앱 폴더 내에 있는 views.py와 충돌하지 않도록 다른 이름을 사용한 것이다.





Template 덮어쓰기

위의 view까지만 추가하면 관리자 페이지에 로그인할 때 나오는 페이지를 사용한다. template을 커스터마이징하고 싶다면(아마 대부분 그럴 것이다) login.html, logged_out.html 파일을 추가해주면 된다.

※ 주의 : 템플릿을 덮어쓸 때 login.html, logged_out.html이라는 이름을 그대로 유지한다.



registration 폴더

앱 폴더의 templates 하위 폴더에 registration 폴더를 만들고, login.html, logged_out.html 파일을 저장한다. myblog와 같이 templates 폴더 내에 있는 앱 이름의 폴더에는 base.html, index.html 등 개발자가 만든 템플릿을 저장한다.


※ templates 폴더 안에 앱 이름과 같은 폴더를 한 번 더 만드는 이유?

Django는 Templates 폴더 경로를 따로 지정해주지 않는 이상 각 앱에 있는 Templates 폴더를 찾는다. 이때, 폴더 이름이 다 Templates이므로 Django가 어느 앱의 Templates 폴더인지 알 수 없으므로 각 앱의 템플릿 폴더를 구분해주기 위해 같은 이름의 폴더를 한 번 더 만들어 템플릿 파일을 저장하는 것이다.


└─myblog(앱 이름)
    ├─templates
    │  ├─registration # 계정 관련 template 파일 저장
    │  └─myblog # 개발자가 만든 template 파일 저장
    └─...



가장 간단한 형태의 login.html


<ul>
{% if user.is_active %} 
    <!--로그인 상태면 아이디 / logout 이 뜨고-->
    <li><a href="{%url 'login' %}"></a></li>
    <li><a href="{% url 'logout' %}">Logout</a></li>
{% else %} 
    
    <!--로그인 상태가 아니면 login / admin이 뜬다.-->
    <li><a href="{% url 'login' %}"> Login</a></li>
    <li><a href="{% url 'admin:index' %}">Admin</a></li>
{% endif %}
</ul>



가장 간단한 형태의 logged_out.html

    <h2> Good Bye. </h2>
    <p><a href="{%url 'login'%}">
        다시 로그인하기 
    </a></p>





프로젝트 폴더의 Settings.py


앱 위치 옮기기

앱 폴더의 login.html로 기존 템플릿을 덮어쓰기 위해서는 'django.contrib.admin', 'django.contrib.auth'보다도 상위에 존재해야 한다. 앱을 아래에 추가했다면, 맨 위로 위치를 옮겨준다.


INSTALLED_APPS = [
    '앱 이름(app name)', # 맨 위에 app name 
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]



이전 페이지로 돌아가기

login 한 뒤 accounts/profile로 리다이렉트 되어 에러가 생기는 경우 프로젝트 폴더의 settings.py 에 login_redirect_url을 정해준다.


LOGIN_REDIRECT_URL = '../../'





Template 디자인

base.html로 템플릿 확장

템플릿을 여러 개 만들다보면 내비게이션이나 푸터와 같이 계속 반복해서 써줘야 하는 코드들이 있다. 이런 경우, 반복되는 코드는 base.html(다른 이름도 상관 없다.)로 만들고 {% extends 'reviewBoard/base.html' %}처럼 다른 템플릿에서 이를 확장해서 쓸 수 있다. 확장하고 싶은 부분은 {% block content %}{% endblock %}의 템플릿 태그 사이에 작성해주면 된다.


base.html의 내비게이션에 로그인 링크를 추가한다.



{% load static %}
<html lang="ko">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- 부트스트랩 추가 (Add Bootstrap) -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.0/css/bootstrap.min.css">
    <title>Site Name</title>

  </head>

  <body>

    <!-- 내비게이션에 login 링크 추가 -->
    <ul class="nav justify-content-end">
        {% if user.is_active %}
        <li class="nav-item">
            <a class="nav-link" href="{% url 'login' %}">{{user.username}}</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="{% url 'logout' %}">logout</a>
        </li>
        {% else %}
        <li class="nav-item">
          <a class="nav-link" href="{%url 'login' %}"> Login</a>
        </li>
        {% endif %}
      </ul>

    <!-- 템플릿 확장을 위한 템플릿 태그 - Block -->
    {% block content %}
    {% endblock %}


  </body>
    <!-- JavaScript -->
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.0/js/bootstrap.min.js" integrity="sha384-7aThvCh9TypR7fIc2HV4O/nFMVCBwyIUKL8XCtKE+8xgCgl/PQGuFsvShjr74PBp" crossorigin="anonymous"></script>
  
</html>



디자인 추가한 login.html

class에 있는 my, mt같은 경우는 내가 자체적으로 spacing.css를 만들어 margin이나 padding을 클래스로 정의해놓은 것이다. 따라서, class 안에서 my- 또는 mt- 부분은 지우고, 직접 margin을 주고 싶다면 태그 안의 style="margin-top:2rem; margin-bottom:2rem;"과 같은 형태로 줄 수 있다. 예를 들면 이렇다. <div class="..." style="margin-top:2rem; margin-bottom:2rem;">

{%csrf_token%}같은 경우는 보안을 위해 Django에서 필수적으로 요구하는 템플릿 태그다.



{% extends 'Your_App_Name/base.html' %}

{% block content %}

<div class="jumbotron jumbotronfluid">

<div class="container my-5" >

    <h3 class="my-3">Login</h3>

    <hr>

    {% if form.errors %}
    <p style="color:red;">아이디, 비밀번호가 일치하지 않습니다. 다시 시도해주세요.</p>
    {% endif %}

    {% if next %}
        {% if user.is_authenticated %}
            <p> 페이지에 대한 접근 권한이 없습니다. 접근 권한을 가진 계정으로 로그인해주세요.</p>
        {% else %}
            <p>페이지를 보시려면 로그인을 해주세요.</p>
        {% endif %}
    {% endif %}

    <form method="post" action="{% url 'login' %}">
    {% csrf_token %}


    <div class="form-group row">
            <label for="staticEmail" class="col-sm-2 col-form-label">ID</label>
            <div class="col-sm-10 mt-1">
              {{ form.username }}
            </div>
          </div>
          <div class="form-group row">
            <label for="inputPassword" class="col-sm-2 col-form-label">Password</label>
            <div class="col-sm-10 mt-1">
                {{ form.password }}
            </div>
          </div>


    <button class="btn btn-info mt-3" type="submit"> Sign in </button>
    <input type="hidden" name="next" value="{{ next }}">
    </form>

    {# Assumes you setup the password_reset view in your URLconf #}
    <p class="mt-2"><a href="{% url 'password_reset' %}">비밀번호를 잊으셨나요?</a></p>


</div>

</div>
{% endblock %}



디자인 추가한 logged_out.html


{% extends 'Your_App_Name/base.html' %}

{% block content %}
<div class="container">

    <h2 class="mt-5"> Good Bye. </h2>
    <p class="mt-3">
        <a href="{%url 'login'%}">
            <button class="btn btn-info"> 다시 로그인하기 
            </button>
        </a>
    </p>

</div>
{% endblock %}