前のパートに戻る 完了して次のパートへ  

  1-2 サインアップとログイン画面を作る

URLルーティングとはドメイン以下の文字列ごとにアクセスする機能を呼び出すものです。例えばhttp://localhsot/loginというURLがあれば ドメイン部分のlocalhostより下の/loginというパスからログイン機能を呼び出したり、http://localhost/accounts/satoshi なら/accounts/satoshiというパスからアカウント機能でsatoshiを呼び出すということになります。

まずはtechpitgram/techpitgram/urls.pyに設定を書き込んでいきます。[プロジェクト名]/[プロジェクト名]/urls.pyはすべてのアクセスの一番最初に呼ばれるURLルーティングの設定ファイルです。 ここでアプリケーションごとのurls.pyに振り分けたりします。

修正:techpitgram/techpitgram/urls.py

from django.contrib import admin
from django.urls import path, include  # 修正  urlsのファイルを読み込むincludeを追加
from django.views.static import serve  # 後に使うviewsのファイルを追加 
from django.conf import settings  # プロジェクトの設定を読み込むプログラムを呼び出す部分を追加


urlpatterns = [
    path('admin/', admin.site.urls),
    path('accounts/', include('django.contrib.auth.urls')),  # 追加
    path('accounts/', include('accounts.urls')),  # accountsアプリのurlsを読み込む処理を追加
    path('media/<path:path>', serve, {'document_root': settings.MEDIA_ROOT}),  # プロジェクト設定を呼び出して画像のためのパス設定を追加
]

新しくtechpitgram/accounts/urls.pyを作成しておきます。

新規作成:techpitgram/accounts/urls.py

from django.urls import path


# アプリ名を記述
app_name = 'accounts'

# ここの配列の中にルーティングを書いていきます。
urlpatterns = [
    
]

テンプレートを用意する

テンプレートとは最終的に出力するデータを組み立てる部品のことです。一度の出力で同じ部品を繰り返し表示したり、複数のURLで同じテンプレートを呼び出したりと、部品を再利用する事ができます。 今回はHTMLを出力するために利用します。 HTML記法内では変数やメゾットなどを呼び出して使うことも出来ます。


ディレクトリを作る

techpitgram/templatesディレクトリを作成します。このタイミングでのディレクトリ構造は以下のようになります。

.
├── Pipfile
├── Pipfile.lock
└── techpitgram
    ├── accounts
    │   ├── __init__.py
    │   ├── admin.py
    │   ├── apps.py
    │   ├── migrations
    │   │   ├── 0001_initial.py
    │   │   └── __init__.py
    │   ├── models.py
    │   ├── tests.py
    │   ├── urls.py
    │   └── views.py
    ├── db.sqlite3
    ├── manage.py
    ├── techpitgram
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    └── templates


settings.py に設定を追加する。

作ったtemplatesディレクトリを設定に反映させます。

修正: techpitgram/techpitgram/settings.py

︙
略
︙
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')], # 修正  テンプレートが入っているディレクトリを指定します
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
︙
略 
︙

これでいつでもテンプレートを使う用意が出来ました。


ログイン画面

ログインに関してはDjangoがすでに処理を持っていてくれているのでHTMLだけ用意してあげます。

すべて1つのディレクトリに入れると管理が大変になりますから新しくregistrationディレクトリを作ってlogin.htmlを新規作成しましょう。registrationはDjangoの認証の仕組みを使うとデフォルトで使うテンプレートディレクトリになっています。

また{{[変数名]}}と表示されているのはview層から送られてきたデータを表示するためのものです。 {%[関数名]%}となっている部分、今回の{% csrf_token %}は何かしらのテンプレートでの処理を行う部分です。{% csrf_token %}はクロスサイトリクエストフォージェリという攻撃を防ぐためのコードでformタグの部分には、基本的に全部に挿入しておきます。

詳細はDjango2.1ドキュメント|クロスサイトリクエストフォージェリ (CSRF) 対策を見てみてください。

新規作成: techpitgram/templates/registration/login.html

またログイン後に表示する先を指定して置きましょう。

修正: techpitgram/techpitgram/settings.py

︙
(略)
︙
LOGIN_REDIRECT_URL = '/'

ここまで来たらログインページが完成です。

早速確認してみましょう。再度pipenv run python manage.py runserverで起動させて確認します。

http://localhost:8000/accounts/login/


サインアップ画面

Django ではログイン処理などは用意されていますが、サインアップは用意されていないので作っていきます。

ここからはDjangoの思想であるMTVに則って書いていきます。 MTVとはユーザーのリクエストを処理するView層とデータの定義操作するModel層そして情報をレンダリングするためのTemplate層の3つの頭文字をとったものになります。 大雑把な処理順は以下のようになります。 


今回は深く触れていきませんが他のフレームワークではMVCモデルと呼ばれるものとほぼ同じ仕組みです。

リクエストを処理するビュー層とデータを操作するモデル層によってユーザーに必要な処理を行い、最終的にはテンプレート層でユーザーに見てもらえるように画面を作成してユーザーに提示します。


forms.pyを作成する。

Djangoには入力フォームに関する処理を手伝ってくれる機能があります。今回はユーザー登録をするフォームを作成していくのを手伝って貰います。新しくtechpitgram/accounts/forms.pyを作成して処理を書いていきます。

今回はUserCreationFormを継承してSignUpFormクラスを定義しています。UserCreationFormはユーザーを作成するためのクラスです。

またここで正しく入力されているかを検証することが出来ます。このような処理をバリデーション(validation)とよびます。

もし、バリデーションに関してより深く知りたい方は バリデータ | Django ドキュメント | Djangoを参照してみてください。

今回はパスワードに数字とアルファベットが含まれていることを確認したいので入力されたものを正規表現という処理で確認していきます。

正規表現はDjangoではなくPythonに実装されているものです。他の言語でも正規表現を対応しているものが多いのでもし興味があれば正規表現について調べてみてください。

Pythonでの正規表現についてはPython3 ドキュメント 6.2. re — 正規表現操作を参照してみてください。

新規作成: techpitgram/accounts/forms.py

from django.contrib.auth.forms import UserCreationForm
from django import forms
from django.core.validators import MinLengthValidator
from django.utils.translation import ugettext_lazy

from .models import User


class SignUpForm(UserCreationForm):
    class Meta:
        # 使うモデルの指定です。定義したものを使います。
        model = User
        # ここではフォームで入力するフィールドを指定しています。
        fields = ("username", "password1", "password2", "icon")

    # 入力したパスワードの検証(バリデーション)を行っています
    def clean_password(self):
        # 入力されたパスワードを取得します
        password = self.cleaned_data.get('password1')
        # 数字とアルファベットが含まれているのかチェックします。
        if not re.search(r'\d', password):
            raise forms.ValidationError('数字が含まれていません')
        if not re.search(r'[a-zA-Z]', password):
            raise forms.ValidationError('アルファベットが含まれていません')
        return password

views.pyに処理を追加する。

作成したforms.pyをつかってviews.pyに処理を書いていきましょう。認証用のSignUpViewクラスとサインアップ後にユーザー情報を見るためのAccountDetailViewクラスを定義します。

今回はジェネリッククラスビューと呼ばれる機能を使って実装していきます。

ジェネリッククラスビューとは必要ないろいろな処理をDjangoが実装していてそれに対して自分たちで処理を追加できるようになっています。

Djangoには様々なジェネリッククラスビューが存在します。今回はCreateViewDetailViewが使われています。それ以外にもよく使うジェネリッククラスビューは以下のとおりです。

参考: クラスベースビュー | Django ドキュメント | Django

修正:techpitgram/accounts/views.py

from django.shortcuts import render
from django.views import generic
from django.urls import reverse
from django.views.generic.detail import DetailView
from django.contrib.auth import login

from .forms import SignUpForm
from .models import User


# サインアップ画面
class SignUpView(generic.CreateView):
    # 使うformクラス設定
    form_class = SignUpForm
    # 使うテンプレートファイル設定
    template_name = 'registration/signup.html'

    # 成功時にログイン処理を行ってAccountDetailViewに飛ぶ
    def get_success_url(self):
        form = self.get_form()
        # usernameから登録したユーザー情報を参照
        user = User.objects.get(username=form.data.get('username'))

        # ログイン処理を行う
        login(self.request, user)
        return reverse(
            'accounts:userDetail',
            kwargs={'username': user.username })

# アカウント詳細画面設定
class AccountDetailView(DetailView):
    model = User
    # urlのパスクエリを引数に取る(後述)
    slug_field = 'username'
    slug_url_kwarg = 'username'

テンプレートを作成する

テンプレートを定義していきます。

新規作成: techpitgram/templates/registration/signup.html

またユーザー詳細画面も作成しましょう。詳細画面は登録とはまた外れるのでtemplates内に新しくaccountsディレクトリを新しく作成してその中に作ります。

新規作成: techpitgram/templates/accounts/user_detail.html

urls.pyを記入する

urlによって各クラスに処理を振るためのルーティングを記入していきます。またユーザー詳細ページに関してはユーザー名をURLに含めるように指定ます。これはTwitterなどでも一緒で最後にユーザー名が入っています。

例: https://twitter.com/techpit_jp

これはパス内にある<変数名>をクラスで受け取る様に実装しています。例えばtechpitというユーザーが入れば以下のようなURLになります。 http://localhost:8000/accounts/techpit

修正: techpitgram/accounts/urls.py

from django.urls import path
from . import views

app_name = 'accounts'

urlpatterns = [
    path('signup/', views.SignUpView.as_view(), name='signup'),# ユーザー追加のパスを追記
    path('<username>/', views.AccountDetailView.as_view(), name='userDetail'),  #ユーザー詳細画面へのパスを追記
]

このタイミングでのディレクトリ構造は以下の様になっています。

.
├── Pipfile
├── Pipfile.lock
└── techpitgram
    ├── accounts
    │   ├── __init__.py
    │   ├── admin.py
    │   ├── apps.py
    │   ├── forms.py
    │   ├── migrations
    │   │   ├── 0001_initial.py
    │   │   └── __init__.py
    │   ├── models.py
    │   ├── tests.py
    │   ├── urls.py
    │   └── views.py
    ├── db.sqlite3
    ├── manage.py
    ├── media
    │   └── image
    │       └── ここに画像が貯まる
    ├── techpitgram
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    └── templates
        ├── accounts
        │   └── user_detail.html
        └── registration
            ├── login.html
            └── signup.html

ここまで来ると登録ができるようになります。早速試してみましょう。再度pipenv run python manage.py runserverで起動させて確認します。 http://127.0.0.1:8000/accounts/signup/ 


登録後はユーザー画面に飛んでユーザー名とアイコンが表示されるのを確認してみましょう。 



画像が大きすぎますね。 画像を最適なサイズにするため次からはスタイルとヘッダーを追加していきます。

議論

4 質問

このコースの評価は?