django1.5でパスワードリセット

ほとんどdjangoが仕組みを用意してくれてるんだけど、サンプルアプリを作って動かしてみたのでメモ
ドキュメントを読まずにやってるので、適当にやってエラー発生→直すの流れになっています



まずurls.pyにpassword_resetを定義

from django.contrib.auth.views import password_reset


url(r'^password_reset/?$', password_reset, name='password_reset'),


アクセスするとエラー

NoReverseMatch at /password_reset
Reverse for 'django.contrib.auth.views.password_reset_done' with arguments '()' and keyword arguments '{}' not found.


password_reset関数の以下の箇所でエラーになってるので

    if post_reset_redirect is None:
        post_reset_redirect = reverse('django.contrib.auth.views.password_reset_done')

kwargsを渡してpost_reset_redirectを指定してやる

from django.contrib.auth.views import password_reset, password_reset_done
from django.core.urlresolvers import reverse_lazy

url(r'^password_reset/?$', password_reset, {'post_reset_redirect': reverse_lazy('password_reset_done')}, name='password_reset'),
url(r'^password_reset_done/?$', password_reset_done, name='password_reset_done')


再びアクセスすると、今度はテンプレートがない

TemplateDoesNotExist at /password_reset
		     registration/password_reset_form.html


template_nameもkwargsで指定して、

from django.contrib.auth.views import password_reset, password_reset_done
from django.core.urlresolvers import reverse_lazy


url(r'^password_reset/?$',
        password_reset,
        {'post_reset_redirect': reverse_lazy('password_reset_done'),
         'template_name': 'apps/password_reset_form.html'},
        name='password_reset'),
url(r'^password_reset_done/?$', password_reset, name='password_reset_done')


適当にhtmlを作成
apps/password_reset_form.html

<h1>{% trans "Password reset" %}</h1>

<p>{% trans "Forgotten your password? Enter your email address below, and we'll email instructions for setting a new one." %}</p>

<form action="" method="post">{% csrf_token %}
{{ form.email.errors }}
<p><label for="id_email">{% trans 'Email address:' %}</label> {{ form.email }} <input type="submit" value="{% trans 'Reset my password' %}" /></p>
</form>


画面が表示された


メールが飛ぶはずなので、メール設定をsettings.pyに追加する

settings.py

EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'hoge@gmail.com'  # 使用するgmailアカウント
EMAIL_HOST_PASSWORD = 'hoge'     # 使用するgmailアカウントのパスワード
EMAIL_PORT = 587


syncdbのときに作成したsuperuserのメールアドレスを入力すると以下のエラーに
メール本文のテンプレートのようです。

TemplateDoesNotExist at /password_reset
registration/password_reset_email.html

email_template_nameでメール本文のテンプレートを指定して

    url(r'^password_reset/?$',
        password_reset,
        {'post_reset_redirect': reverse_lazy('password_reset_done'),
         'template_name': 'apps/password_reset_form.html',
         'email_template_name': 'apps/password_reset_email.html'}, # 追加
        name='password_reset'),
    url(r'^password_reset_done/?$', password_reset_done, name='password_reset_done')


djangoからパクってきてhtmlを用意
apps/password_reset_email.html

{% load i18n %}{% autoescape off %}
{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}

{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'django.contrib.auth.views.password_reset_confirm' uidb36=uid token=token %}
{% endblock %}
{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}

{% trans "Thanks for using our site!" %}

{% blocktrans %}The {{ site_name }} team{% endblocktrans %}

{% endautoescape %}


またurlエラーに

NoReverseMatch at /password_reset
Reverse for 'django.contrib.auth.views.password_reset_confirm' with arguments '()' and keyword arguments '{u'uidb36': u'1', u'token': u'3gy-f8a8a25bf12e3d2d0641'}' not found.


password_reset_email.html内部でurl引いている箇所を修正

{% load i18n %}{% autoescape off %}
{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}

{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb36=uid token=token %} {# この行を修正 #}
{% endblock %}
{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}

{% trans "Thanks for using our site!" %}

{% blocktrans %}The {{ site_name }} team{% endblocktrans %}

{% endautoescape %}


urls.pyにpassword_reset_confirmを追加

    url(r'^password_reset/?$',
        password_reset,
        {'post_reset_redirect': reverse_lazy('password_reset_done'),
         'template_name': 'apps/password_reset_form.html',
         'email_template_name': 'apps/password_reset_email.html'},
        name='password_reset'),
    url(r'^password_reset_done/?$', password_reset_done, name='password_reset_done'),
    url(r'^password_reset_confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', password_reset_confirm, name='password_reset_confirm')

メールは送信されたけどそのあとの遷移でエラー

TemplateDoesNotExist at /password_reset_done
registration/password_reset_done.html


テンプレートパスを指定して、、

    url(r'^password_reset/?$',
        password_reset,
        {'post_reset_redirect': reverse_lazy('password_reset_done'),
         'template_name': 'apps/password_reset_form.html',
         'email_template_name': 'apps/password_reset_email.html'},
        name='password_reset'),
    url(r'^password_reset_done/?$',
        password_reset_done,
        {'template_name': 'apps/password_reset_done.html'}, # 修正
        name='password_reset_done'),
    url(r'^password_reset_confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', password_reset_confirm, name='password_reset_confirm')


htmlを用意
apps/password_reset_done.html

{% load i18n %}

{% block title %}{% trans 'Password reset successful' %}{% endblock %}

{% block content %}

<h1>{% trans 'Password reset successful' %}</h1>

<p>{% trans "We've emailed you instructions for setting your password to the email address you submitted. You should be receiving it shortly." %}</p>

{% endblock %}


パスワードリセット後の画面が表示されるようになりました

飛んできたメールはこんなのです

You're receiving this email because you requested a password reset for your user account at example.com.

Please go to the following page and choose a new password:

http://example.com/password_reset_confirm/1-3gy-f8a8a25bf12e3d2d0641/

Your username, in case you've forgotten: yuhei

Thanks for using our site!

The example.com team


ホスト名だけlocalhost:8000にかえてpassword_reset_confirにアクセスしたら次のエラーに

NoReverseMatch at /password_reset_confirm/1-3gy-f8a8a25bf12e3d2d0641/
Reverse for 'django.contrib.auth.views.password_reset_complete' with arguments '()' and keyword arguments '{}' not found.


またpost_reset_redirectをreverseで引こうとしてエラ−になってます。


password_reset_confirmでpost_reset_redirectを指定します
urls.py

   url(r'^password_reset/?$',
        password_reset,
        {'post_reset_redirect': reverse_lazy('password_reset_done'),
         'template_name': 'apps/password_reset_form.html',
         'email_template_name': 'apps/password_reset_email.html'},
        name='password_reset'),
    url(r'^password_reset_done/?$',
        password_reset_done,
        {'template_name': 'apps/password_reset_done.html'},
        name='password_reset_done'),
    url(r'^password_reset_confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
        password_reset_confirm,
        {'post_reset_redirect': reverse_lazy('password_reset_complete')}, # 修正
        name='password_reset_confirm'),
    url(r'^password/reset/complete/$',
        password_reset_complete,
        name='password_reset_complete'),


テンプレートが無いエラー

TemplateDoesNotExist at /password_reset_confirm/1-3gy-f8a8a25bf12e3d2d0641/
registration/password_reset_confirm.html


password_reset_confirmのkwargsでテンプレートを指定して

    url(r'^password_reset/?$',
        password_reset,
        {'post_reset_redirect': reverse_lazy('password_reset_done'),
         'template_name': 'apps/password_reset_form.html',
         'email_template_name': 'apps/password_reset_email.html'},
        name='password_reset'),
    url(r'^password_reset_done/?$',
        password_reset_done,
        {'template_name': 'apps/password_reset_done.html'},
        name='password_reset_done'),
    url(r'^password_reset_confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
        password_reset_confirm,
        {'post_reset_redirect': reverse_lazy('password_reset_complete'),
         'template_name': 'apps/password_reset_confirm.html'}, # 修正
        name='password_reset_confirm'),
    url(r'^password/reset/complete/$',
        password_reset_complete,
        name='password_reset_complete'),


htmlを用意
apps/password_reset_confirm.html

{% load i18n %}

{% if validlink %}

<h1>{% trans 'Enter new password' %}</h1>

<p>{% trans "Please enter your new password twice so we can verify you typed it in correctly." %}</p>

<form action="" method="post">{% csrf_token %}
{{ form.new_password1.errors }}
<p class="aligned wide"><label for="id_new_password1">{% trans 'New password:' %}</label>{{ form.new_password1 }}</p>
{{ form.new_password2.errors }}
<p class="aligned wide"><label for="id_new_password2">{% trans 'Confirm password:' %}</label>{{ form.new_password2 }}</p>
<p><input type="submit" value="{% trans 'Change my password' %}" /></p>
</form>

{% else %}

<h1>{% trans 'Password reset unsuccessful' %}</h1>

<p>{% trans "The password reset link was invalid, possibly because it has already been used.  Please request a new password reset." %}</p>

{% endif %}

表示された


新しいパスワードを入力すると、そろそろ先回りしとけって感じだけどテンプレートエラーに

TemplateDoesNotExist at /password/reset/complete/
registration/password_reset_complete.html

urls.py

    url(r'^password_reset/?$',
        password_reset,
        {'post_reset_redirect': reverse_lazy('password_reset_done'),
         'template_name': 'apps/password_reset_form.html',
         'email_template_name': 'apps/password_reset_email.html'},
        name='password_reset'),
    url(r'^password_reset_done/?$',
        password_reset_done,
        {'template_name': 'apps/password_reset_done.html'},
        name='password_reset_done'),
    url(r'^password_reset_confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
        password_reset_confirm,
        {'post_reset_redirect': reverse_lazy('password_reset_complete'),
         'template_name': 'apps/password_reset_confirm.html'},
        name='password_reset_confirm'),
    url(r'^password/reset/complete/$',
        password_reset_complete,
        {'template_name': 'apps/password_reset_complete.html'}, # 修正
        name='password_reset_complete'),


apps/password_reset_complete.html

{% load i18n %}

<h1>{% trans 'Password reset complete' %}</h1>

<p>{% trans "Your password has been set.  You may go ahead and log in now." %}</p>

<p><a href="{{ login_url }}">{% trans 'Log in' %}</a></p>


完了ページも表示された。

これでpassword_resetできるようになった