見出し画像

『超入門』Djangoで作る初めてのウェブアプリケーション Part8(Userアプリ, ヘッダーの設定)

このシリーズは『超入門』Djangoで作る初めてのウェブアプリケーション Part7(CRUD, Bootstrap)の続きです。

複数ユーザーが利用することを想定して、ユーザー管理の為にUserアプリを作ります。

user_appの作成

Djangoには有難いことにユーザーの認証機能が初めから用意されています。

それをカスタムして好きなカラムを作ることやログイン時の必要入力項目を変更することなどできます。

今回はカスタムは行いません。そのまま使っていきます。

(公式では、Djangoのユーザーモデルをそのまま使うことは推奨されていません)

アプリの作成はPart3(アプリケーションとは?)で行っているので忘れた方は見直してください。

ターミナル

python manage.py startapp user_app

setting.pyに登録

#省略
INSTALLED_APPS = [
   'django.contrib.admin',
   'django.contrib.auth',
   'django.contrib.contenttypes',
   'django.contrib.sessions',
   'django.contrib.messages',
   'django.contrib.staticfiles',
   'blog_app',
   'django_cleanup',
   'bootstrap4',
   'widget_tweaks',
   'user_app' #追加
] #省略

プロジェクトディレクトリ(blog)のurls.pyの設定。

Django/blog/blog/urls.py

from django.urls import path, include
from django.contrib import admin
from django.conf import settings      
from django.conf.urls.static import static

urlpatterns = [
   path('admin/', admin.site.urls),
   path('', include('blog_app.urls')),
   path('', include('user_app.urls')), #追加
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


blog_appのpathと同じようにURLが空の場合にuser_appのurls.pyを読み込みます。

user_app内にはurls.pyが存在しない為、自身で作成して下のようにコードを書きます。

スクリーンショット 2020-04-29 11.53.35

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

app_name = 'user_app'
urlpatterns = [
  path('login/', auth_views.LoginView.as_view(template_name='user_app/login.html'), name='login'),
  path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]

コード説明です。

3行目のfrom django.contrib.auth import views as auth_viewsを使用することで、ログイン、ログアウト機能が簡単に実現できます

7行目のpath('login/', auth_views.LoginView.as_view(template_name='user_app/login.html'), name='login'),

urlがloginの場合にDjangoが用意しているauth_views.LoginView.as_viewを使って専用のページを返します。関数の引数にtemplate_nameとリンク時に使用する、nameを設定ます。

元々用意されているクラスや関数は直感的で非常にわかりやすいです。

あとはtemplate_nameで指定した、login.htmlのHTMLファイルをtemplates/user_appディレクトリ内に作成すれば完成です。

(今回の場合はviews.pyにログイン、ログアウト用の関数を書く必要はありません。)

Django/blog/templates/user_app/login.html

<h2>Login</h2>
<form method="post">
 {% csrf_token %}
 {{ form.as_p }}
<button type="submit">Login</button>
</form>

最後にsettings.pyにログインURLと、ログイン後、ログアウト後のURLの設定をします。

#省略
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/' #追加
LOGIN_URL = 'user_app:login'
LOGIN_REDIRECT_URL = 'blog_app:index'
LOGOUT_REDIRECT_URL = 'blog_app:index'

これでログイン、ログアウトが完成です。

http://127.0.0.1:8000/login/にアクセスしましょう。

スクリーンショット 2020-04-29 13.20.00

実際にスーパーユーザーを作ったときのユーザー名とパスワードを入力して成功するとindex.htmlが表示されます。

ログインに成功したら、http://127.0.0.1:8000/logout/にアクセスしましょう。またindex.htmlが表示されたと思います。

本当にログアウトできているか確認するために、http://127.0.0.1:8000/admin/にアクセスして下の画像のようにログインを要求されたらログアウトに成功しています。

スクリーンショット 2020-04-29 13.23.51

ユーザーの新規登録機能

Djangoでは認証機能は用意されているのですが、新規登録などは自身で作る必要があります

まずは新規登録に使用するforms.py(フォーム)を作成します。

Desktop/Django/blog/user_app/forms.pyを作り下のように作ります。

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User

class SignUpForm(UserCreationForm):
  class Meta:
      model = User
      fields = ('username', 'email', 'password1', 'password2')

コード説明です。

2行目のUserCreationFormをインポートすることで、Djangoがデフォルトで用意している、ユーザー登録用のフォームが使用可能になります。

3行目でUserモデルをインポートします。

今回のクラス名はSignUpFormで、modelにインポートしたUserモデルを代入して、fieldsにカラムを代入します

これで新規登録用のフォームが完成です。

ここからはお決まりの順番でurls.py→views.py→templatesで行います。

/Django/blog/user_app/urls.py

app_name = 'user_app'
urlpatterns = [
  path('login/', auth_views.LoginView.as_view(template_name='user_app/login.html'), name='login'),
  path('logout/', auth_views.LogoutView.as_view(), name='logout'),
  path('signup/', views.signup, name='signup'), #追加
]

/Django/blog/user_app/views.py

from django.shortcuts import render, redirect
from .forms import SignUpForm
from django.contrib.auth import authenticate, login
from blog_app .models import Post

# Create your views here.
def signup(request):
  signup_form = SignUpForm(request.POST or None)
  if request.method == "POST" and signup_form.is_valid():
      user = signup_form.save()
      input_username = signup_form.cleaned_data['username']
      input_email = signup_form.cleaned_data['email']
      input_password = signup_form.cleaned_data['password1']
      user = authenticate(username=input_username, email=input_email, password=input_password)
      login(request, user)
      return redirect('blog_app:index')
  context = {
      "signup_form": signup_form,
  }
  return render(request, 'user_app/signup.html', context)

後で説明しますが、3行目のfrom django.contrib.auth import authenticate, loginsignup関数の重要な部分です。

signup関数内ですが、SignUpForm(request.POST or None)で新規登録ページに遷移したのか、POSTメソッドでフォームの内容が送信されたのか判別して、その結果をsignup_form変数に代入します。

そして、 if request.method == "POST" and signup_form.is_valid():メソッドがPOSTで尚且つ送信されたデータの内容にエラーがないか確認して、signup_form.save()で保存して、user変数に代入しています。

続いて、usernameとemail、passwordをcleaned_data関数にかけて、それぞれinput....変数に代入して、authenticate変数でそれらを認証します。

最後にlogin関数を使い、新規登録完了して、尚且つログイン状態になります

残りのコードはadd関数やedit関数ほぼ同じです。

signup.htmlを作ろう

templates/user_app/signup.html

{% extends 'base.html' %}
{% block content %}

      <form class="form-signin" method="post">{% csrf_token %}
        <h1>Sign up</h1>
        {{ signup_form.as_p }}
        <button type="submit">Sign up</button>
      </form>
  <p>既にアカウントをお持ちですか?? <a href="{% url 'user_app:login' %}">Login</a></p>
</div>
</div>
{% endblock %}

これで新規登録ページの準備が整いました。

http://127.0.0.1:8000/signup/にアクセスしてみましょう。

表示結果

スクリーンショット 2020-04-29 20.48.47

実際に新規ユーザーを登録してみましょう。

登録した後、adminページのユーザー覧に追加されていると新規登録が機能が正常に動いています。

スクリーンショット 2020-04-29 20.51.32

新規登録ページとログインページの見た目を整えよう

Part7(見栄えを Bootstrapで整えよう)で見た目の設定について簡単な説明をしたので、忘れた方は確認してください。

signup.html

{% extends 'base.html' %}
{% load widget_tweaks %}
{% block content %}
<h1 class="mt-5 pt-4 text-center">Signup</h1>
 <form class="form-signin" method="post">
   {% csrf_token %}
   <label for="id_username" class="sr-only">タイトル</label>
   <input type="text" name="username" placeholder="名前" maxlength="150" class="form-control mb-3" required id="id_username" autofocus>

   <label for="id_email" class="sr-only">メールアドレス</label>
   <input type="email" name="email" placeholder="メールアドレス" maxlength="254" class="form-control mb-3" required id="id_email">

   <label for="id_password1" class="sr-only">パスワード</label>
   <input type="password" name="password1" placeholder="パスワード" autocomplete="new-password" class="form-control mb-3" id="id_password1">

   <label for="id_password2" class="sr-only">パスワード(確認用)</label>
   <input type="password" name="password2" placeholder="パスワード(確認用)" autocomplete="new-password" class="form-control mb-3" required id="id_password2">

   <button type="submit" class="btn btn-block btn-outline-success">Signup</button>
 </form>
  <p>既にアカウントをお持ちですか?? <a href="{% url 'user_app:login' %}">Login</a></p>
</div>
</div>
{% endblock %}

表示結果

スクリーンショット 2020-04-29 21.06.32

login.html

{% extends 'base.html' %}
{% load widget_tweaks %}
{% block content %}
<h1 class="mt-5 pt-4 text-center">Login</h1>
<form method="post">
{% csrf_token %}
<label for="id_username" class="sr-only">ユーザー名</label>
<input type="text" name="username" placeholder="ユーザー名" autofocus autocapitalize="none" autocomplete="username" maxlength="150" class="form-control mb-3" required id="id_username">

<label for="id_password" class="sr-only">パスワード</label>
<input type="password" name="password" autocomplete="current-password" placeholder="パスワード" class="form-control mb-3" required id="id_password">

<button type="submit" class="btn btn-block btn-outline-success">Login</button>
</form>
{% endblock %}

表示結果

スクリーンショット 2020-04-29 21.13.11

ヘッダー のリンク設定

現在ヘッダーはただの置き物になっています。ヘッダー が最低限の役割を果たすように、下のように編集しましょう。

#省略   
<nav class="navbar fixed-top navbar-expand-lg navbar-light bg-light">
     <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarTogglerDemo02" aria-controls="navbarTogglerDemo02" aria-expanded="false" aria-label="Toggle navigation">
       <span class="navbar-toggler-icon"></span>
     </button>
     <a class="navbar-brand" href="{% url 'blog_app:index' %}">ブログサイト</a>
   
     <div class="collapse navbar-collapse" id="navbarTogglerDemo02">
       <ul class="navbar-nav mr-auto mt-2 mt-md-0">
         {% if request.user.is_authenticated %} #注目
         <li class="nav-item">
           <a class="nav-link" href="#">{{request.user.username}}</a>
         </li>
         <li class="nav-item">
           <a class="nav-link" href="{% url 'blog_app:add' %}">投稿</a>
         </li>
         <li class="nav-item">
           <a class="nav-link" href="{% url 'user_app:logout' %}">ログアウト</a>
         </li>
         {% else %}
         <li class="nav-item">
           <a class="nav-link" href="{% url 'user_app:signup' %}">新規登録</a>
         </li>

         <li class="nav-item">
           <a class="nav-link" href="{% url 'user_app:login' %}">ログイン</a>
         </li>
         {% endif %}
       </ul>
     </div>
   </nav> #省略

ヘッダー の中身がほとんど変わってしまうのですが、コードは至ってシンプルです。

重要な部分は{% if request.user.is_authenticated %}です。

複数のユーザーが登録して使用できるようになったので、リクエストしたユーザーが認証(ログイン)されているか、if文を使って判断します

その結果、ログインしていないユーザーにはログインか新規登録を要求するように表示が切り替わります

<a class="nav-link" href="#">{{request.user.username}}</a>のリンクはPart9で作成します。

ログイン前

スクリーンショット 2020-04-29 22.10.01

ログイン後

スクリーンショット 2020-04-29 22.09.31

だいぶウェブアプリケーションっぽくなってきました。

次回はユーザーの詳細ページと編集、削除を作っていきます。

Takuのおすすめ図書

Pythonの基礎以外にも、著者本人が未経験からPythonを独学で学んだ方法や、エンジニアとしての心構えさらには、米国ですが仕事探しのノウハウまで書かれていて、各章には挫折しないために名言も書かれています。今まで読んできた技術書とは少し違って面白いです。

Djangoの技術書は何冊か読み比べましたが、どれもアカデミックです。以下もアカデミックといえばそうですが、この『超入門』Djangoで作る初めてのウェブアプリケーション終了後には、比較的容易に理解できるかと思います。チャレンジしてみてください。

『超入門』Djangoで作る初めてのウェブアプリケーション Part9(ユーザーの詳細、編集、ページの作成と削除)

この記事が気に入ったら、サポートをしてみませんか?
気軽にクリエイターの支援と、記事のオススメができます!
Level up!
7
1988年(S63)生まれのTakuです。 自動車エンジニアを経験後、IT企業でRuby, Pythonエンジニアとしてウェブサービスの開発とプログラミング講師をして、 現在は実家に帰省して家業である工業刃物の研磨をしております。 趣味は音楽、コンピューター、読書、筋トレ!

こちらでもピックアップされています

『超入門』Djangoで作る初めてのウェブアプリケーション
『超入門』Djangoで作る初めてのウェブアプリケーション
  • 16本

Djangoフレームワーク初心者を対象に、Bootstrapを使用した簡単なデザインを装飾し、ウェブアプリの基本の「基」を学べる事ができます。

コメント (1)
非常に分かりやすく、初学者の私でもここまでサクサク進めることができ、大変ありがたいです!なぜか、「ユーザーの新規登録機能」部分で躓いてしまっていますが、色々調べながら進めてみます。
コメントを投稿するには、 ログイン または 会員登録 をする必要があります。