pyhaya’s diary

プログラミング、特にPythonについての記事を書きます。Djangoや機械学習などホットな話題をわかりやすく説明していきたいと思います。

Django でログインページを作る

PythonフルスタックWebフレームワークとして有名な Django を使ってログインページを簡単に作ってみます。

開発環境

準備

雛形の生成

Django のプロジェクトをセットアップします。

$ mkdir myapp
$ cd myapp
$ django-admin startproject config .
$ python manage.py startapp myauth
$ python manage.py startapp appmain
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py createsuperuser  # ユーザー名とパスワードを設定する

これらを実行することで以下のようなディレクトリ構成が得られます。

$ tree -L 2
.
├── appmain    # 内部ページ
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   ├── models.py
│   ├── tests.py
│   ├── views.py
├── config    # プロジェクト全体の設定
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── db.sqlite3
├── manage.py
└── myauth    # 今回ログインページをつくるところ
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── migrations
    ├── models.py
    ├── tests.py
    └── views.py
基本的な設定

config/settings.py

# ...
LOGIN_REDIRECT_URL = "/"  # ログイン後にどこに飛ばすか
LOGIN_URL = "/myauth"  # ログインページの URLを設定

# ...

INSTALLED_APPS = [
    "myauth.apps.MyauthConfig",  # <- 追加
    "appmain.apps.AppmainConfig",  # <- 追加
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
]

# ...

config/urls.py

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

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", include("appmain.urls")),
    path("myauth/", include("myauth.urls")),
]

appmain/urls.py

from django.urls import path
from appmain import views

urlpatterns = [path("", views.index, name="index")]

myauth/urls.py

from django.urls import path
from myauth import views

app_name = "myauth"
urlpatterns = [path("", views.Login.as_view(), name="login")]
内部ページの実装

ログインしたあとに飛ぶページを作ります。これは今回の主題ではないので簡単に作ります。上の appmain/urls.py に設定したように、ルートページとして views.index を表示するようにしているので、これを作ります。

appmain/views.py

from django.shortcuts import render
from django.contrib.auth.decorators import login_required


@login_required
def index(request):
    return render(request, "appmain/index.html")

呼ばれたら index.html を表示するだけです。シンプルですね。

appmain/templates/appmain/index.html

<html>
  <head></head>
  <body>This is inner page</body>
</html>

Django では HTML ファイルは慣習的に (app名)/templates/(app名)/ ディレクトリに入れるということになっていますので少しパス名が長くなります。

ログインページの実装

まずはログイン情報を入力するフォームを作ります。

myauth/forms.py

from django.contrib.auth.forms import AuthenticationForm


class LoginForm(AuthenticationForm):
    def __init__(self, *args, **kwargs):
        super(LoginForm, self).__init__(*args, **kwargs)

Django には認証用のフォームを作るためのクラスが用意されているのでそれを継承すれば良いです。このフォームをビューに組み込みます。

myauth/views.py

from django.contrib.auth.views import LoginView

from myauth.forms import LoginForm


class Login(LoginView):
    form_class = LoginForm
    template_name = "myauth/index.html"

これでログインページの実装は9割方終わりです。あとは HTML ファイルを作ります。

myauth/templates/myauth/index.html

<html>
  <head>
    <title>Login Page</title>
  </head>
  <body>
    <h2>Login</h2>
    <form method="post" action="{% url 'myauth:login' %}">
      {% csrf_token %}
      {{ form.username }}
      {{ form.password }}
      {% if form.errors %}
      <p>ユーザー名またはパスワードが一致しません</p>
      {% endif %}
      <input type="submit" value="login"/>
    </form>
  </body>
</html>

ビューの中でフォームを取り込んでいるので、HTML内では LoginFormの持つ変数を使うことができます。この記事では明示的にフォーム内で変数を定義することはしていませんが、AuthenticationFormusernamepasswordを定義しているのでそれを HTML 内で {{ form.username }}のようにして使うことができます。

github.com

フォームのアクションとして myauth:loginを指定しています。これは「myauth」という名前空間内の「login」というビューにフォームの内容を送信するということを指定しています。「myauth」の urls.py 内を見直してみると

path("", views.Login.as_view(), name="login")

という記述があります。myauth:loginlogin は、この name="login" を指しています。

実行してみる

では、今まで実装してきたコードを試してみます。

$ python manage.py runserver

として http://localhost:8000/myauth にアクセスしてみます。

f:id:pyhaya:20200922202208p:plain

CSS は何も書いていないので非常にシンプルですがきちんとログインページが出来ています。一番最初に管理者としてユーザーを1人登録していますのでそのユーザーのユーザー名とパスワードを入力すれば内部ページに飛べます。間違っていれば ユーザー名またはパスワードが一致しません という文字が表示されるはずです。