Djangoでログイン画面を作成する

Python Django Bootstrap4

概要

Djangoで、会員登録機能を自作するシリーズの1つです。前回で、メールアドレスをユーザー名として使うカスタムユーザーを定義しました。今回はログイン画面を実装していきます。

ログインしていない場合は、トップページの上にログインページへのリンクが表示されます。
ログインしていない場合はログインリンクが表示

ログインページは、今のところシンプルです。
シンプルなログインページ

パスワードを間違ったりすると、エラーが表示されますね。
パスワードを間違うとちゃんとエラー表示

無事にログインすると、デフォルトではトップページへリダイレクトします。ログインしているので、ログアウト用のリンクができていますね。
ログイン後の画面

ログインページの設定

settings.pyを編集します。ログイン画面を何処にするかの設定と、ログインした後のリダイレクト先の設定を書きます。reverse関数に渡せるような形で、文字列として定義することができます。

LOGIN_URL = 'register:login'
LOGIN_REDIRECT_URL = 'register:top'

URL定義

当然ですが、プロジェクトのurls.pyで読み込ませることも必要です。

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('register.urls')),
]

また、アプリケーション内のurls.pyも編集が必要です。トップページ、ログイン、ログアウトですね。

from django.urls import path
from . import views

app_name = 'register'

urlpatterns = [
    path('', views.Top.as_view(), name='top'),
    path('login/', views.Login.as_view(), name='login'),
    path('logout/', views.Logout.as_view(), name='logout'),
]

models.pyやadmin.pyは、前回と変わりがありません。

ログイン用フォームの作成

forms.pyです。ログイン用のフォームを作成し、Bootstrap4対応させます。 今回はラベルを使わず、placeholder内にラベルを表示させる方法を使います。 カスタムユーザーでもデフォルトユーザーでも、問わず使えます。

from django.contrib.auth.forms import (
    AuthenticationForm
)


class LoginForm(AuthenticationForm):
    """ログインフォーム"""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs['class'] = 'form-control'
            field.widget.attrs['placeholder'] = field.label  # placeholderにフィールドのラベルを入れる

ログイン・ログアウトビュー

views.pyです。トップページは単純なTemplateViewで、ログインとログアウトはDjangoに用意されたビューを使います。

from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import (
    LoginView, LogoutView
)
from django.views import generic
from .forms import LoginForm


class Top(generic.TemplateView):
    template_name = 'register/top.html'


class Login(LoginView):
    """ログインページ"""
    form_class = LoginForm
    template_name = 'register/login.html'


class Logout(LoginRequiredMixin, LogoutView):
    """ログアウトページ"""
    template_name = 'register/top.html'

ベーステンプレートの作成

base.htmlとして作成しておきます。{% if user.is_authenticated %}を使って、ログイン済みならログアウト用のリンクを、そうでなければログイン用のリンクを表示させています。

<!doctype html>
<html lang="ja">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
          integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">

    <title>会員登録サンプル</title>
</head>
<body>
    <!-- ナビバー -->
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
      <a class="navbar-brand" href="{% url 'register:top' %}">ホームページ名</a>
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>

      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav mr-auto">
          {% if user.is_authenticated %}
          <li>
            <a class="nav-item nav-link" href="{% url 'register:logout' %}">ログアウト</a>
          </li>
          {% else %}
          <li class="nav-item">
            <a class="nav-item nav-link" href="{% url 'register:login' %}">
            ようこそ、ゲスト!ログインはこちら
          </a>
          </li>
          {% endif %}
        </ul>
      </div>
    </nav>

    <!-- メインコンテント -->
    <div class="container mt-3">
        {% block content %}{% endblock %}
    </div>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
            integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
            crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"
            integrity="sha384-cs/chFZiN24E4KMATLdqdvsezGxaGsi4hLGOzlXwp5UZB1LY//20VyM2taTB4QvJ"
            crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"
            integrity="sha384-uefMccjFJAIv6A+rW+L4AHf99KvxDjWSu1z9VI8SKNVmz4sk7buKt/6v9KI65qnm"
            crossorigin="anonymous"></script>
</body>
</html>

トップページ

top.htmlです。便宜上用意しただけのページです。

{% extends "register/base.html" %}
{% block content %}
<p>ここに、好きな内容を入れる。</p>
{% endblock %}

ログインページ

login.htmlです。<div class="col-md-6 offset-md-3">のように書くと、良い具合に入力部分を中央寄せできます。それ以外は、よくあるフォームですね。

{% extends "register/base.html" %}
{% block content %}
<form action="" method="POST">
    <div class="col-md-6 offset-md-3">
        <div class="card">
            <div class="card-body">
                {{ form.non_field_errors }}
                {% for field in form %}
                    {{ field }}
                    {{ field.errors }}
                    <hr>
                {% endfor %}
                <button type="submit" class="btn btn-success btn-lg btn-block" >ログイン</button>
                <input type="hidden" name="next" value="{{ next }}" />
                {% csrf_token %}
            </div>
        </div>
    </div>
</form>
{% endblock %}

Relation Posts

Djangoで会員登録機能を自作するシリーズ

Djangoで会員登録機能を自作していきます。メールアドレスをユーザー名として使うようにし、ログイン画面、仮登録、メールクリックで本登録、ユーザー情報変更ページ、パスワード変更ページ、パスワードを忘れた際の再設定...などなど、よくある一連の機能を実装します。

Python Django シリーズ・まとめ

Comment

記事にコメントする

タムラショウ

いつも参考にさせていただいております。

ログイン後の処理について質問させてください。

【やりたいこと】 ログイン後、トップページのテンプレート内で{% if user.is_authenticated %}とするのではなく、user_detail.htmlなどの、パラメータがついたページに飛ばしたい

【試したやり方】 1.settings.py内の LOGIN_REDIRECT_URL = 'register:top'を変える →セキュリティエラー

2.トップページに1度戻し、ログイン状態であればリダイレクトさせる →冗長な気がする

何かベストプラクティスはあるのでしょうか。

調べ足りず申し訳ありませんが、ご教授いただけますと幸いです。

返信する

なりと

ログインビューを次のように変更してください。

class Login(LoginView):
    """ログインページ"""
    form_class = LoginForm
    template_name = 'register/login.html'

    def get_success_url(self):
        url = self.get_redirect_url()
        return url or resolve_url('register:user_detail', pk=self.request.user.pk)

名無し

すごい!! できました!!

ご丁寧にありがとうございます。