[Django] 日本ひげ男協会のサイトを作成する。その5
注意
この記事は、id:SumiTomohiko:20070126:1169809341の続きです。
ログイン
ここまでで、会員を登録し、一覧表示する機能がなんとかできました。あと必要な機能は、自分の情報を編集し、あるいは退会する機能です。これを実現するためには、ログインとログアウトの機能が必要です。というわけで、まずログインを実装します。
Djangoの認証システム
ところで、Djangoには独自の認証システムがついています。しかし、これにはいくつか問題があります。
- ユーザを表すクラスに、django.contrib.auth.models.Userクラスを使わなければならない。このクラスには、first_nameやlast_nameといった、認証には関係せず、アプリケーションでも必要がない属性がついている。継承して使う方法もドキュメントには記されていない。
- 何より、juma.user.models.Userクラスを既に作ってしまっている。
というわけで、今回はDjangoが用意している認証システムは利用せず、自前でログインとログアウトを実装します。
Djangoの認証システムというのは、settings.pyにある、
INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'juma.user', 'django.contrib.admin', )
のうち、django.contrib.authアプリケーションを指します。独自に認証システムを実装するのなら、これを削除してもいいのですが、それはできません。なぜならば、管理アプリケーションであるdjango.contrib.adminアプリケーションが、django.contrib.authアプリケーションに依存しているためです。django.contrib.adminも削除するのならdjango.contrib.authも削除できるのですが、管理アプリケーションも使いたいと思うので、これらはこのまま残しておくことにします。
ログイン
では、ログインを作成します。ログインするURLは、/user/login/にします。user/urls.pyは、以下のようになります。
from django.conf.urls.defaults import * from juma.user.models import User urlpatterns = patterns('', (r'^add/$', 'juma.user.views.add'), (r'^list/$', 'django.views.generic.list_detail.object_list', { 'queryset': User.objects.all(), 'allow_empty': True, 'paginate_by': 20 }), (r'^media/image/(?P<file_name>[-\w\d_\.]+)$', 'juma.user.views.image'), (r'^login/$', 'juma.user.views.login'), ) # vim: tabstop=4 shiftwidth=4 expandtab
次に、ビューを作成します。最終的に、以下のようになりました。
def login(request): manipulator = juma.user.manipulators.LoginManipulator() if request.POST: new_data = request.POST.copy() errors = manipulator.get_validation_errors(new_data) if not errors: manipulator.do_html2python(new_data) try: user = User.objects.get(account=new_data["account"]) if user.password != new_data["password"]: raise User.DoesNotExist except User.DoesNotExist: _add_error(errors, "account", "アカウント名またはパスワードが違います。") else: request.session[USER_ID_KEY] = user.id return _redirect_list() else: errors = new_data = {} form = forms.FormWrapper(manipulator, new_data, errors) return render_to_response('user/login.html', {"form": form})
Userオブジェクトを得たのち、パスワードを比較するという単純なものです(パスワードは、そのうちハッシュにするかもしれません)。認証に成功したら、USER_ID_KEY ("_user_id") というキーで、セッションにUserクラスのIDを設定します。その後、一覧画面に遷移します。
juma.user.manipulators.LoginManipulatorクラスは、user/manipulators.pyに記述します。
class LoginManipulator(forms.Manipulator): def __init__(self): self.fields = ( forms.TextField(field_name="account", length=16, is_required=True), forms.PasswordField(field_name="password", length=16, is_required=True), )
アカウント名を入力する欄と、パスワードを入力する欄があるだけです。余計な情報を与えないために、maxlength属性もヴァリデータもつけません。
残りは、テンプレートです。template/user/login.htmlにしました。
<h1>ログイン</h1> <form action="" method="POST"> <div class="login"> <p> <table> <tr> <td>アカウント名</td> <td> {{ form.account }} {% for error in form.account.errors %} {{ error|escape }} {% endfor %} </td> </tr> <tr> <td>パスワード</td> <td> {{ form.password }} {% for error in form.password.errors %} {{ error|escape }} {% endfor %} </td> </tr> </table> </p> <p> <center><input type="submit" value="ログインする"/></center> </p> </div> </form> <!-- vim: tabstop=4 shiftwidth=4 expandtab -->
以上で、ログインの実装は完了です。/user/loginをブラウザで開くと、ログインが面画が表示されます。
なお、ログインすると、データベースのdjango_sessionテーブルにセッションの情報が保存されます。
$ sqlite3 data.sqlite [~/projects/juma] SQLite version 3.3.5 Enter ".help" for instructions sqlite> select * from django_session; 91a18ca60354426aa3cac4f329b2b51f|KGRwMQpTJ191c2VyX2lkJwpwMgpJMQpzLmE2ZTA2MGI2MDBlOTQ3ZGUzMGUxYjdhNTgyYmFiMTU5
2007-02-09 08:37:45.764221 |
ログアウト
残りの機能はログアウトです。/user/logoutにアクセスしたら、ログアウトするようにします。user/urls.pyは、以下のようになります。from django.conf.urls.defaults import * from juma.user.models import User urlpatterns = patterns('', (r'^add/$', 'juma.user.views.add'), (r'^list/$', 'django.views.generic.list_detail.object_list', { 'queryset': User.objects.all(), 'allow_empty': True, 'paginate_by': 20 }), (r'^media/image/(?P<file_name>[-\w\d_\.]+)$', 'juma.user.views.image'), (r'^login/$', 'juma.user.views.login'), (r'^logout/$', 'juma.user.views.logout'), ) # vim: tabstop=4 shiftwidth=4 expandtabビューは、以下の通りです。
def logout(request): try: del request.session[USER_ID_KEY] except KeyError: pass return _redirect_list()ログアウトには画面がないので、マニピュレータもテンプレートもありません。これで以上です。/user/logout/にアクセスすると、ログアウトし、会員一覧画面に戻ります。django_sessionテーブルから、レコードも削除されます。
$ sqlite3 data.sqlite [~/projects/juma] SQLite version 3.3.5 Enter ".help" for instructions sqlite> select * from django_session;