Date Modified Tags django / python

2021-01-25: 追記

ソーシャルログインだけでなく、通常のログインもやりたかったので、django-allauthを試してみた。

インストール

pipで

pip install django-allauth

ファイルでの設定

settings.pyとurls.pyを設定

# settings.py
INSTALLED_APPS = (
...
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.twitter', #例としてTwitter
)
AUTHENTICATION_BACKENDS = (
...
    'allauth.account.auth_backends.AuthenticationBackend',
)
TEMPLATE_CONTEXT_PROCESSORS = (
...
    "django.core.context_processors.request",
    "django.contrib.auth.context_processors.auth",
    "allauth.account.context_processors.account",
    "allauth.socialaccount.context_processors.socialaccount",
)
SITE_ID = 1
# urls.py
urlpatterns = patterns('',
    ...
    url('^accounts/', include('allauth.urls')),
    url('^accounts/profile/?', include('profile.urls',namespace='profile')), #ログイン後のリダイレクト先
)

adminページでの設定

ソーシャルログインする場合のみ必要。 http://domain/admin/ にアクセスして管理者ログインしてSocial applicationを追加する。 フォーム内では名前を適当に付けて、Twitterの場合Client idにConsumer keyを登録して、Secret keyにConsumer secretを登録すればおk 最後に、利用可能サイトから一番上のサイト(SITE_ID=1と指定してるので)を選択するとおk

http://domain/accounts にアクセスすればログインフォームが出てくる。出来た。

テンプレートを上書きする

プロジェクトディレクトリ/templates/account以下にファイルを設定すればおk 例えばログインのテンプレートなら、login.htmlを設置すればおk

元のファイルはgithubを見れば分かる

追記

/templates/account以下ならokではなく、TEMPLATESのDIRSで

TEMPLATES = [
    {
....
        'DIRS': [
            os.path.join(BASE_DIR, 'templates'),
            os.path.join(BASE_DIR, 'templates','account'),
        ],
...
    }
]

みたいにパスを追加しておけば、どのフォルダでもok。

使える機能

githubのコード 見れば大体分かる感じ

ユーザー登録時のメール確認後の処理でハマる

ユーザー登録すると通常は登録したメールアドレスにメールが届いて、そこに書いてあるURLにアクセスすると登録完了する手順が表示される。そこらへんの文章とかも上のテンプレート上書きでいけて問題ないんだけど、初期状態では登録が最後まで完了すると、そのままログインしてログイン時のリダイレクト先に移動してしまう。完了画面を表示したい場合はこれではまずい。

ので、ここらへんのCustom Redirectsの項目を参考にしてアダプタを作ってみた

# settings.py
ACCOUNT_ADAPTER = 'project.users.adapter.MyAccountAdapter'
# project/users/adapter.py
from django.conf import settings
from allauth.account.adapter import DefaultAccountAdapter

class MyAccountAdapter(DefaultAccountAdapter):
    def get_email_confirmation_redirect_url(self,request):
        path = "/account/complete"
        return path

でもこれだけでは上手くいかなかった。普通にログイン時のリダイレクト先に移動してしまった。どうもACCOUNT_LOGIN_ON_EMAIL_CONFIRMATIONをFalseにしないとダメみたい

# settings.py
ACCOUNT_LOGIN_ON_EMAIL_CONFIRMATION = False

これでやっと/account/completeにリダイレクトしてくれた。ログインした状態ではダメみたいなので、ログインは再度やってもらわないといけない。うーん今のとこ仕方ないか・・・。

django-allauthのサインアップフォームをカスタマイズしたい

あるフィールドにhelp_textを付ける

参考:Overwrite django-allauth form field - Stack Overflow

__init__を上書きして、フィールドに属性を追加する コードはこんな感じ。例としてユーザー名入力フォームにヘルプテキストとして「required」という文字を追加する

# appname/forms.py
from django import forms

class SignupForm(forms.Form):
  def __init__(self, *args, **kwargs):
    super(SignupForm, self).__init__(*args, **kwargs)
    self.fields['username'].help_text = "required"
# settings.py
ACCOUNT_SIGNUP_FORM_CLASS = "appname.forms.SignupForm"

こんな感じ

フィールドのバリデーションを追加

参考:python - How to clean username with Django allauth adapter? - Stack Overflow

Account Adapterを設定してあげて、そこでclean_xxxを作ると上手くいくみたい

```py
# project/users/adapter.py
class MyAccountAdapter(DefaultAccountAdapter):
    ...
    def clean_username(self, username):
        " 適当に処理を入れる
        " エラーの場合はraise Exception
        return username

メッセージの変更

例えばログインメッセージは

templates\/account\/messages\/logged_in.txt

にあったりするので、DIRSで通したパスの下にフォルダを作って配置すれば上書きできる・・・はず。

参考:How to clean up Django login message from framework

リンクの貼り方

loginページなどへリンクが貼りたい時のやりかた

<a href="{% url 'account_login' %}">ログイン</a>
<a href="{% url 'account_logout' %}">ログアウト</a>
<a href="{% url 'account_signup' %}">サインアップ</a>
<a href="{% url 'account_change_password' %}">パスワード変更</a>
<a href="{% url 'account_inactive' %}">退会</a>

みたいにする

django-allauthのログインリンクのはり方

django-allauth/allauth/account/urls.py

登録時のEmail認証にGmailを使う

django-allauth - Send email verification using Gmail account

ここそのままでいけた。

EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = DEFAULT_FROM_EMAIL = 'gmail account'
EMAIL_HOST_PASSWORD = 'gmail password'

usernameを使わない

setting.pyで

ACCOUNT_USER_MODEL_USERNAME_FIELD = 'username'
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_EMAIL_REQUIRED = True

こんな感じでよさげ。

django allauth empty username causes duplicate key in postgress DB