三人寄れば文殊の知恵

Two heads are better than one, the more the merrier.

Django のユーザー認証を二段階認証に対応する [ 準備編 ]

こんにちは、Catchball21 技術部の梅田です。

これから何回かに分けて、Django を使い、2段階認証に対応したアプリケーションの作成方法をご紹介したいと思います。今回は準備編です。

2段階認証とは

皆さんWebサービスを利用する際には、ユーザーIDとパスワードを利用していると思います。2段階認証とは、ユーザーIDとパスワード以外に新たにもう1つ要素を追加して、認証方式を強化するシステムのことです。追加する要素として下記のアイテムが主流になっています。

  • USBトークン
  • スマートカード
  • バイオメトリクス(指紋認証,静脈認証,網膜認証,声紋認証)
  • ワンタイムパスワード

2段階認証の必要性

近年、特定のWebサービスが何者かに攻撃されIDとパスワードが盗まれるという事件が頻発しています。そういった行為に対処する方法の1つとして2段階認証が注目され始めています。 日本では数年前から、オンラインバンキングやMMORPGなどで利用されていますが、他分野でも導入の検討や、新たに導入した企業が複数あるようです。

主要なWebサービスは、2段階認証を提供している

主要なWebサービスは、2段階認証を提供しています。以下がそのリストになります。

Djangoで2段階認証を実装するには

今回はワンタイムパスワードを利用し、2段階認証を実装する方法をご紹介します。 Djangoでの認証の実装方法は、いくつかあります。 最も簡単な方法は Bouke Haarsma さんが作成した django-two-factor-auth というモジュールを利用する方法です。

次回は、このモジュールを利用し Django で2段階認証をコーディングする方法をご紹介したいと思います。

Django チュートリアル[テンプレート]

こんにちは。Catchball21 技術部の森本です。

本日はTemplate(テンプレート)についてご説明します。
DjangoによるWebアプリ開発のチュートリアルは今回で最後になります。

Template(テンプレート)

まずは前回最後のパートで作成したindex.htmlについて復習しましょう。

index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>SimpleBoard</title>
  </head>
  <body>
    <form action="/" method="post">

    {% csrf_token %}
    {{ form }}
    <input type="submit" value="登録">
    </form>

    {% for entry in entries %}

    <p>{{ entry.entry }}</p>

    {% endfor %}

  </body>
</html>

基本的にはhtmlそのものですが、{{ entry.entry }}{% for entry in entries %}等、いくつか見慣れない構文がみられますね。

Djangoのテンプレートでは変数タグを使用することができます。
上記では{{ entry.entry }}変数{% for entry in entries %}{% csrf_token %}タグにあたります。

テンプレート中で変数は{{ spam }}と記載します。
コンテキストでspam: 1として渡した場合、テンプレート中の{{ spam }}1に置き換えられます。

タグはテンプレート内で何らかの処理を行いたいときに使用します。
テンプレート中でタグ{% egg %}と記載されます。
例えば、テンプレート中で分岐処理を行いときは、{% if ... %}タグ、ループ処理を行いたい時は{% for ... %}タグ等が標準で用意されています。
もしくは、タグは自分で定義することもできます。

前回作成したindex viewでテンプレートに渡されたコンテキストを確認しましょう。

index.html
1
2
3
4
5
6
7
8
9
10
11
12
    entries = Board.objects.all()
    form = BoardForm()
    return render_to_response(
        'index.html',
        context_instance=RequestContext(
            request,
            {
                'form': form,
                'entries': entries
            }
        )
    )

上記ではコンテキストとして、form変数にはBoardFormオブジェクト、entries変数にはBoardモデルのquerysetが渡されています。
Formオブジェクトをテンプレートに渡した場合、テンプレート中でHTMLのフォームとして展開します。
querysetはイテレータブルなオブジェクトなので、index.htmlでは{% for ... %}タグを使用して、格納されているオブジェクトを取り出しています。

最後にBootStrapで少しレイアウトを整えたindex.htmlを記載します。

index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>SimpleBoard</title>
    <!-- Latest compiled and minified CSS -->
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">

    <!-- Optional theme -->
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.min.css">

    <!-- Latest compiled and minified JavaScript -->
    <script src="//code.jquery.com/jquery.js"></script>
    <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
  </head>
  <body>

    <nav class="navbar navbar-default" role="navigation">
    <!-- Brand and toggle get grouped for better mobile display -->
      <div class="navbar-header">
        <a class="navbar-brand" href="#">SimpleBoard</a>
      </div>
    </nav>

    <div class="row">
      <div class="col-md-4"></div>
      <div class="col-md-4">
        <form class="form-horizontal" role="form" action="/" method="post">

          {% csrf_token %}


          <div class="form-group">
            <div class="col-lg-10">

              {{ form.entry }}

            </div>
          </div>
          <div class="form-group">
            <div class="col-lg-offset-2 col-lg-10">
              <button type="submit" class="btn btn-default">登録</button>
            </div>
          </div>
        </form>


        {% for entry in entries %}
          <div class="panel panel-default">
            <div class="panel-body">
              {{ entry.entry }}
            </div>
          </div>
        {% endfor %}

      </div>
      <div class="col-md-4"></div>
    </div>
  </body>
</html>

python manage.py runserverで開発サーバを起動して、http://127.0.0.1:8000にアクセスすると下記のような画面が表示されると思います。
this is a SimpleBoard

最後に

いささか駆け足でDjangoによるWebアプリ開発について解説してまいりましたが、いかがでしたか。
DjangoによるWebアプリ開発の利便性を、多少なりとも感じて頂ければ幸いです。

今回使用したサンプルの完全版は、以下で参照することができます。
shnmorimoto / django_sample_simple_board — Bitbucket

また時間の都合上、今回のチュートリアルで解説できなかったTopicsの一部を以下に記載します。
参考になりそうな、参照先も記しますので、お時間あるときにご覧になってみてください。

Django チュートリアル[view(ビュー)作成]

こんにちは。Catchball21 技術部の森本です。

DjangoによるWebアプリ開発のチュートリアルも今回が3回目になります。
本日はview(ビュー)の作成についてご説明します。

MTVモデル

ビューの説明に移る前に、DjangoのMTVモデルについてご紹介します。
MTVモデルはおよそ下記のようなイメージになります。

this is a MVT Model Image

Djangoにおいて、ユーザからリクエストを受け取った際の処理の流れは下記の通りです。

  1. URLディスパッチにより、リクエストされたURLパターンにマッチしたview関数を呼び出す。
  2. フォームからGETやPOSTでデータを受け取った際は適宜Formオブジェクトを呼び出し、validationを行う。
  3. Modelを通して,DBからデータを取得する。
  4. 必要なテンプレートを呼び出し、レスポンスを返す。

今回説明するviewの最低限の役割は、下記になります。

  • リクエストを受け取る。
  • レスポンスを返す。

Formの作成

viewの作成に移る前に、まずはFormオブジェクトを作成しましょう。

Webアプリケーションでの悩みどころの一つとして、validationの扱いがあります。
DjangoではこのようなForm処理を簡易に扱う為にフォーム処理ライブラリが標準で付属されています。

フォーム処理ライブラリは、validation以外にも下記の機能を持っています。

  1. フォームウィジェットから、 HTML フォームを自動的に生成して表示できます。
  2. 提出されたデータに対して、バリデーション規則 (validation rule) を適用できます。
  3. バリデーションエラーを検出したときに、フォームをエラーメッセージ付きで表示できます。
  4. 提出されたデータを、適切な Python のデータ型に変換できます。

フォームの操作 — Django 1.4 documentation

ではFormオブジェクトを作成しましょう。Formオブジェクトはforms.pyで定義します。
myproject/apps/simpleboard/ディレクトリにforms.pyを作成し、下記を記載して下さい。

forms.py
1
2
3
4
5
6
7
8
from django import forms

from .models import Board

class BoardForm(forms.ModelForm):

  class Meta:
      model = Board

上記ではBoardFormクラスの中でmodelとして、Boardモデルを指定しています。
たったこれだけのコードで、Model(Boardモデル)から紐付けて、Boardモデルに必要なFormオブジェクトを定義することができます。

では、続いてviewの作成に移りましょう。

viewの作成

Djangoのviewは実際にはResponseオブジェクトを返すPythonの関数になります。
と言っても、何のことか伝わりずらいので、実際に作成してみましょう。

ちなみにDjangoでは1.3から、より汎用的なクラスベースのviewが導入されています。
今回は関数ベースのviewを使用しますが、機会があれば、また別途クラスベースのviewについても解説したいと思います。

viewはviews.pyの中で定義します。
myproject/apps/simpleboard/views.pyを開いて、下記のように書き換えて下さい。

views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from django.shortcuts import redirect
from django.shortcuts import render_to_response
from django.shortcuts import redirect
from django.template import RequestContext

from .models import Board
from .forms import BoardForm


def index(request):

    if request.method == "POST":
        form = BoardForm(request.POST)
        if form.is_valid():
            entry = form.cleaned_data["entry"]
            print entry
            Board.objects.create(
                entry=entry
            )
        return redirect('/')

    entries = Board.objects.all()
    form = BoardForm()
    return render_to_response(
        'index.html',
        context_instance=RequestContext(
            request,
            {
                'form': form,
                'entries': entries
            }
        )
    )

viewの処理の流れは、概ね下記の内容です。

  1. リクエストのメソッドによって、処理を振り分け
  2. それぞれの処理で必要であれば、モデルからデータを取得
  3. テンプレートを呼び出し、レスポンスを返す

上記のviews.pyの例では、必要なモジュールのインポート定義の後、def index(request):からがviewの定義になります。 リクエストを受け取ってからの処理は下記の通りです。

  1. リクエストのメソッドがPOSTかどうかをチェックします。(12行目)
  2. POSTデータをFormオブジェクトに渡し、validationのチェックをかけます(13, 14行目)
  3. validationが通っていたら、受け取ったデータをBoardに登録し、トップにリダイレクトするレスポンスを返します。(15-20行目)
  4. Boardモデルから全てのデータを取得します。(22行目)
  5. Formオブジェクトを生成します。(23行目)
  6. テンプレート(index.html)を呼び出し、レスポンスを返します。またテンプレート内で変数のように使用できるコンテキストもこの時に指定します。(24-33行目)

テンプレートとして、index.htmlを指定していますが、まだ作成はしていないですよね。 myproject/templates/index.htmlを作成して、下記を記載してください。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>SimpleBoard</title>
  </head>
  <body>
    <form action="/" method="post">
    
    {% csrf_token %}
    {{ form }}
    <input type="submit" value="登録">
    </form>

    {% for entry in entries %}

    <p>{{ entry.entry }}</p>

    {% endfor %}
    
  </body>
</html>

テンプレートの詳細については、次回ご紹介させて頂きます。

最後にURLとviewとをマッピングさせる必要があります。
URLとviewとのマッピングはmyproject/urls.pyに記載します。
下記のように記載して下さい。

urls.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from django.contrib import admin
from django.conf.urls import patterns, include, url

from apps.simpleboard.views import index


# See: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#hooking-adminsite-instances-into-your-urlconf
admin.autodiscover()


# See: https://docs.djangoproject.com/en/dev/topics/http/urls/
urlpatterns = patterns('',
    # Admin panel and documentation:
    url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
    url(r'^admin/', include(admin.site.urls)),
    url(r'^$', index)
)

url関数の一つ目の引数にurlのパターン、2つ目の引数にそのurlにマッピングさせたいviewを指定します。 上記の場合はドメイン名(例:http://localhost)にアクセスした際にindexのviewを返すようマッピングしています。

では開発サーバ上でSimpleBoardにアクセスしてみましょう。
プロジェクトのトップディレクトリでpython manage.py runserverを実行して下さい。

(django_tutorial)% python manage.py runserver
Validating models...

0 errors found
August 28, 2013 - 19:27:34
Django version 1.5.2, using settings 'myproject.settings.dev'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

8000番ポートで開発サーバが起動されるので、http://127.0.0.1:8000にアクセスして下さい。
下記のような画面が表示されれば、成功です。

this is a SimpleBoard

view(ビュー)の作成については以上です。
次回はTemplateについてご紹介する予定です。

Django チュートリアル[プロジェクト作成-モデル作成]

こんにちは。Catchball21 技術部の森本です。

蒸し暑い日が続いていますが、体調等は崩されていないでしょうか?
僕は少し夏バテ気味なので、早く涼しくなって欲しいと祈るばかりです。

今回は前回に続いて、DjangoによるWebアプリ開発についてご紹介します。
プロジェクト・アプリ・モデルの各作成について詳しく解説していきます。

作成するWebアプリ

今回のチュートリアルでは、シンプルな掲示板を題材にしています。
完成イメージは下記のようなイメージになります。

this is a SimpleBoard image

フォームから入力し、入力した内容を下部に表示する単純なCRUDを行うWebアプリですね。

プロジェクト作成

まずはプロジェクトを作成しましょう。 Djangoをインストールするとdjango-admin.pyコマンドが併せてインストールされます。 プロジェクト作成はdjango-admin.pyを使用して、作成します。

(django_tutorial)% django-admin.py startproject myproject

上記コマンドを実行するとmyprojectという名前のディレクトリが作成されます。 以後はこのmyproject内で作業をしていくのですが、その前にプロジェクトについてDjangoの便利な機能をご紹介します。

Djangoでは1.4からproject templateという機能が追加されました。
project templateではフォルダ構成や追加した3rd Party のライブラリ等をテンプレート化し、纏めておくことができます。またそれらのテンプレートを使用してプロジェクトを作成することができます。
つまりプロジェクトを通じて得たノウハウをテンプレート化し、次回のプロジェクトでも簡単に使用することができる機能と言えます。
テンプレートはgithub等で公開されているものがあるので、それらを使用することで初心者でもDjangoのベストプラクティスを利用することができます。

project templateについては、hirokikyさんが素晴らしい紹介記事を書いてらっしゃるので、皆さんご覧になってみてください。

今回はdjango-skelというテンプレートを使用したいと思います。
先程作成したmyprojectディレクトリを削除して、下記コマンドを実行し、新たにdjango-skelテンプレートを利用するプロジェクトを作成しましょう。

(django_tutorial)% django-admin.py startproject --template=https://github.com/rdegges/django-skel/zipball/master myproject

myprojectディレクトリが作成されていれば、成功です。

myprojectディレクトリに移動し、必要なライブラリをインストールします。django-skellでは、reqsディレクトリ以下に開発環境(dev.txt)と本番環境(prod.txt)で使用するライブラリを分けて記載しています。まずは開発用のライブラリをインストールするだけで良いでしょう。

(django_tutorial)% pip install -r reqs/dev.txt

アプリ作成

プロジェクトが作成できたら、アプリを作成します。 django-skelではアプリの配置場所としてmyproject/appsが用意されている為、myproject/apps配下に作成します。

(django_tutorial)% cd myproject/apps
(django_tutorial)% python ../../manage.py startapp simpleboard

myproject/apps配下にsimpleboardという名前のディレクトリが作成されていることを確認して下さい。 またsimpleboard配下にはviewとmodelの雛形が作成されます。

(django_tutorial)% ls simpleboard
__init__.py models.py   tests.py    views.py

アプリを作成したら、Djangoに新規作成したアプリを登録する必要があります。
myproject/settings/common.pyを編集して先程作成したsimpleboardを登録しましょう。
LOCAL_APPSに下記のようにsimpleboardを追記します。

common.py
1
2
3
LOCAL_APPS = (
    'apps.simpleboard',
)

モデル作成

アプリの作成まで完了したら、いよいよモデルを作っていきましょう。
まずは今回必要となるモデルについて考えましょう。
今回作成するのはシンプルな一行掲示板の為、最低限入力した内容を保存するカラムだけがあれば問題なさそうです。 SQLで表すとは下記のような感じになるでしょうか。

models.sql
1
2
3
4
CREATE TABLE "simpleboard_board" (
   "id" integer NOT NULL PRIMARY KEY,
   "entry" varchar(255) NOT NULL
);

ではモデルを作成しましょう。
Djangoではmodels.pyがモデルに対応する為、models.pyを編集します。

models.py
1
2
3
4
5
6
from django.db import models


class Board(models.Model):

  entry = models.CharFiled(max_length=255)

上記ではentryというフィールドを持ったBoardモデルを定義しています。 クラスがDBのテーブル、クラスのアトリビュートがDBのカラムに対応しています。

モデルが定義できたら、DBに反映する必要があります。 プロジェクトのトップディレクトリに戻り下記コマンドを実行して下さい。

(django_tutorial)% python manage.py syncdb
Syncing...
Creating tables ...
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_groups
Creating table auth_user_user_permissions
Creating table auth_user
Creating table django_content_type
Creating table django_session
Creating table django_site
Creating table django_admin_log
Creating table south_migrationhistory
Creating table simpleboard_board

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username (leave blank to use '****): admin
Email address: admin@*****
Password:
Password (again):
Superuser created successfully.
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)

Synced:
 > django.contrib.auth
 > django.contrib.contenttypes
 > django.contrib.sessions
 > django.contrib.sites
 > django.contrib.messages
 > django.contrib.staticfiles
 > django.contrib.humanize
 > django.contrib.admin
 > django.contrib.admindocs
 > south
 > compressor
 > apps.simpleboard
 > debug_toolbar

Not synced (use migrations):
 - djcelery
(use ./manage.py migrate to migrate these)

初めてsyncdbを実行した際は、管理者ユーザを作成するかを聞かれます。
yesと入力すると、管理者ユーザに必要な情報(ユーザ名、メールアドレス、パスワード)を聞かれるので、適当なものを入力して下さい。 作成した管理者ユーザはadmin siteへログインする際に使用します。

以上でモデルの作成は完了です。

次回はviewの作成についてご紹介する予定です。

Django チュートリアル[準備編]

こんにちは。Catchball21 技術部の森本です。

これから何回かに分けて、DjangoによるWebアプリ開発についてご紹介しようと思います。
今回は準備編になります。

Djangoって?

と、その前にDjangoをご存知無い方の為に簡単にご紹介します。

DjangoはPythonで書かれたオープンソースのWebアプリケーションフレームワークで、元々はニュース系のサイトを管理する目的で開発されたそうです。 いわゆるオールインワン型のフレームワークで特徴として、MVCパターンによく似た、MTVパターン(Model – Template – View)に従って開発することや標準でリッチな管理インターフェイスを持つこと等が挙げられます。

this is a django web site image

当社でも受託開発や自社サービス開発にDjangoを利用しています。

開発環境

今回のチュートリアルでは下記の環境を想定しています。

  • Mac OS X 10.7
  • Python 2.7
  • Django 1.5

準備

では、早速準備に移って行きましょう。
まずはPythonの仮想環境を構築することができるvirtualenvを導入しましょう。

virtualenvはPythonのパッケージ管理ツールであるpipからインストールすることができます。

% pip install virtualenv

virtualenvのラッパーで仮想環境の管理をしやすくするvirtualenvwrapperも導入しましょう。 こちらもpipでインストールことができます。

% pip install virtualenvwrapper

virtualenv, virtualenvwrapperを使うためにはshellに追加の設定が必要です。
zshを使用している場合は.zshrcに以下の行を追加します。(bashの場合も同じように.bashrcに記述すれば大丈夫だと思います。)

.zhsrc
1
2
3
4
5
if [ -f `which virtualenvwrapper.sh` ]; then
    export WORKON_HOME=$HOME/.virtualenvs
    export VIRTUALENVWRAPPER_PYTHON=/usr/local/bin/python
    source `which virtualenvwrapper.sh`
fi

virtualenvwrapperの導入まで完了したら、仮想環境を作成しましょう。
今回は仮想環境名としてdjango_tutorialを使用します。

% mkvirtualenv django_tutorial
New python executable in django_tutorial/bin/python
Installing setuptools............done.
Installing pip...............done.

shellのプロンプトの先頭に下記のように仮想環境名が表示されていれば、成功です。

(django_tutorial)%

virtualenvwrapperについて簡単に使い方を紹介しておきます。

(django_tutorial)% deactivate #deactivateで仮想環境から抜けることができます。
% workon #workonで作成した仮想環境の一覧を見ることができます。
django_tutorial
% workon django_tutorial # workon <仮想環境名> で仮想環境に入ることができます。
(django_tutorial)% mkvirtualenv hogehoge # mkvirtualenv <仮想環境名> で仮想環境を作成することができます。
New python executable in hogehoge/bin/python
Installing setuptools............done.
Installing pip...............done.
(hogehoge)% deactivate
(hogehoge)% rmvirtualenv hogehoge # rmvirtualenv <仮想環境名>で指定した仮想環境を削除することができます。
Removing hogehoge...

仮想環境の作成まで完了したら、Djangoをインストールします。 こちらもpipからインストールすることができます。

(django_tutorial)% pip install django

以上で準備は完了です!

次回はDjangoのプロジェクト作成からモデルの作成までをご紹介する予定です。