GoogleAppEngine用フレームワーク「Kay」で認証用ユーザーに属性を追加する

GoogleAppEngine用フレームワーク「Kay」で認証用ユーザーに属性を追加する」より。

GoogleAppEngine用フレームワーク「Kay」のデータストア認証で使用するDatastoreUserを継承して属性を追加する方法。

データストア認証で使用するクラスに属性を追加するには、DatastoreUserを継承したクラスを作成します。

総論

ポイントとしては、

  • kay.auth.models.DatastoreUserを継承したクラスを作成する。
  • settings.AUTH_USER_MODELにkay.auth.models.DatastoreUserを継承したクラスを指定する。
  • 登録するときはcreate_new_user()関数を使う。追加した属性はキーワード引数で指定する。

その他は、Kayのドキュメント「1. Kay チュートリアル」「9. 認証の設定」と同じようなものです。

プロジェクトの作成

プロジェクトを作成します。

$ python kay/manage.py startproject myproject
$ cd myproject
$ python manage.py startapp myapp

次のようにファイルが作成されました。

myproject

-- kay/
-- myapp/
-- app.yaml
-- favicon.ico
-- manage.py
-- settings.py

`-- urls.py

settings.pyを編集して、myappを登録します。

settings.py

INSTALLED_APPS = (
'myapp',
)

APP_MOUNT_POINTS = {
'myapp': '/',
}

認証用ミドルウェアを有効にする

settings.MIDDLEWARE_CLASSES に kay.auth.middleware.AuthenticationMiddleware を追加し、認証機構を有効にします。

settings.py

MIDDLEWARE_CLASSES = (
'kay.auth.middleware.AuthenticationMiddleware',
)

ログインボックスを使用するために、settings.INSTALLED_APPS に kay.auth を追加します。

また、settings.CONTEXT_PROCESSORSに kay.auth.context_processors.login_box を追加します。

INSTALLED_APPS = (
'kay.auth',
'myapp',
)

CONTEXT_PROCESSORS = (

'kay.auth.context_processors.login_box',
)

データストア認証を有効にする

データストア認証に必要なSessionMiddlewareを有効にするため、settings.MIDDLEWARE_CLASSES に kay.auth.middleware.SessionMiddleware を追加します。

settings.py

MIDDLEWARE_CLASSES = (
'kay.sessions.middleware.SessionMiddleware',
'kay.auth.middleware.AuthenticationMiddleware',
)

settigns.AUTH_USER_BACKEND に kay.auth.backends.datastore.DatastoreBackend を設定します。

DatastoreUserを継承したクラスMyUserを作成し、認証に使用するクラスとして設定します。

settings.py

AUTH_USER_BACKEND = 'kay.auth.backends.datastore.DatastoreBackend'
AUTH_USER_MODEL = 'myapp.MyUser'

認証用クラスを作成する

DatastoreUserを継承したクラスMyUserを作成します。

address属性を追加します。

myapp/models.py

# -*- coding: utf-8 -*-
from google.appengine.ext import db
from kay.auth.models import DatastoreUser

class MyUser(DatastoreUser):
address = db.TextProperty(u'住所', required=True)

ユーザー登録フォームを作成する

ユーザー登録フォームを作成します。

パスワードの入力を確認するために、パスワードを再入力する入力欄を追加します。

myapp/views.py

from kay.utils import forms
from kay.utils.validators import ValidationError

class MyUserForm(forms.Form):
user_name = forms.TextField(u'ユーザー名', required=True)
password = forms.TextField(u'パスワード', required=True)
password_confirm = forms.TextField(u'パスワードの再入力', required=True, widget=forms.PasswordInput)
address = forms.TextField(u'住所', required=True)

def context_validate(self, data):
'''パスワードの再入力チェック'''
if data['password'] != data['password_confirm']:
raise ValidationError(u'パスワードが一致しません。')

ユーザーの入力処理を作成する

認証ユーザーを登録するときはcreate_new_user()関数を使用します。

モデルに追加した属性は、キーワード引数で指定することで、登録することができます。

create_new_user(form['user_name'], 
password=form['password'],
address=form['address'])

db.Model.put()を使用して登録すると、ログインボックスからログインすることができません。

ユーザー名がすでに登録されているときはDuplicateKeyErrorが発生します。

try:
create_new_user(…)
msg = u'ユーザーを登録しました。'
except DuplicateKeyError:
msg = u'既に同じユーザー名が登録されています。'

myapp/views.py

from kay.utils import forms
from kay.utils.validators import ValidationError
from kay.auth import (create_new_user, DuplicateKeyError)
import models

def index(request):
form = MyUserForm()
msg = u''
if request.method == 'POST':
if form.validate(request.form):
try:
create_new_user(form['user_name'],
password=form['password'],
address=form['address'])
msg = u'ユーザーを登録しました。'
except DuplicateKeyError:
msg = u'既に同じユーザー名が登録されています。'
return render_to_response('myapp/index.html',
{'form': form.as_widget(),
'msg': msg,
'users': models.MyUser.all()})

myapp/templates/index.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Top Page - myapp</title>

</head>
<body>

{% from "auth/macros.html" import render_loginbox with context %}
<div>
{% if request.user.is_anonymous() %}
{{ render_loginbox() }}
{% else %}
Hello {{ request.user }}! <a href="{{ create_logout_url() }}">ログアウト</a>
{% endif %}
</div>

<div>
<p>{{ msg }}</p>
{{ form()|safe }}
</div>

<table>
<tr><th>ユーザー名</th><th>住所</th></tr>

{% for user in users %}
<tr><td>{{user.user_name}}</td><td>{{user.address}}</td></tr>
{% endfor %}
<table>

</body>
</html>