DjangoでGoogleアカウントのアバターを扱えるようにした
以前python-social-authというライブラリを使ってGoogleアカウントでOAuth認証ができるようになりました。
https://hodalog.com/oauth-authentication-in-dja/
デフォルトのままでもいい感じなのですが、アバター画像も引っ張ってこれるようにしたいなぁと思い、実装方法を調べたのでまとめます。
実装方法
実装には、python-social-authのパイプライン機能を使います。
python-social-authのパイプライン機能
パイプラインというのは、一つのTCPコネクションで複数のHTTPリクエストをさばくことです。
python-social-authではパイプラインのメカニズムを利用することで、OAuth認証の間で独自に定義した関数などをねじ込むことができます。
実装手順
あらかじめpython-social-authをインストールし、OAuthが使えるようにしておきます。インストール方法と使い方はこちら↓
https://hodalog.com/oauth-authentication-in-dja/
以下、アバターを使うための設定です。
settings.pyの設定
settings.pyに下記を追加します。
SOCIAL_AUTH_PIPELINE = (
'social_core.pipeline.social_auth.social_details',
'social_core.pipeline.social_auth.social_uid',
'social_core.pipeline.social_auth.auth_allowed',
'social_core.pipeline.social_auth.social_user',
'social_core.pipeline.user.get_username',
'social_core.pipeline.user.create_user',
'social_core.pipeline.social_auth.associate_user',
'social_core.pipeline.social_auth.load_extra_data',
'social_core.pipeline.user.user_details',
'your_application.users.pipeline.get_avatar', # <- pipeline.pyというファイルのget_avatarメソッドを指定
)
your_app.users.pipeline.get_avatar
で、Djangoのアプリケーションにあるpipeline.pyというファイルのパスと、pipeline.puで定義したget_avatarという関数(メソッド)を指定しています。
ファイル名やメソッド名は自由に決めて大丈夫です。
pipeline.pyで独自関数の定義
今回は your_app の users ディレクトリの中の pipeline という指定の仕方をしているので、その場所にファイルをおきます。
your_app/
├── __init__.py
.....
├── users
│ ├── __pycache__
│ └── pipeline.py # <- こんな感じ
.....
pipeline.pyの中身は次のようにしました。
def get_avatar(backend, strategy, details, response,
user=None, *args, **kwargs):
url = None
if backend.name == 'facebook':
url = "http://graph.facebook.com/%!s(MISSING)/picture?type=large"%!r(MISSING)esponse['id']
if backend.name == 'twitter':
url = response.get('profile_image_url', '').replace('_normal','')
if backend.name == 'google-oauth2':
url = response['image'].get('url')
if url:
user.profile.avatar = url
user.save()
実装の予定はありませんが、念のためtwitterとfacebookのアバターも拾えるようにしています。
user.profile.avatar = url
でProfileモデルのavatarという属性にurlが記録されるようにしています。当然、Profileモデルが作られていることが前提になります。
ちなみに私は次のようなモデルを作成しています。
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
gender = models.CharField(max_length=20, blank=True)
birth_date = models.DateField(null=True, blank=True)
location = models.CharField(max_length=30, blank=True)
favorite_words = models.CharField(max_length=50, blank=True)
avatar = models.URLField(max_length=200, blank=True)
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
これでOAuth認証によるユーザー作成に合わせ、アバターのURLが自動でDBに保存されます。
保存できれば、あとはテンプレートで出力するだけです。
...
{%!i(MISSING)f user.profile.avatar %!}(MISSING)
<img src="{{ user.profile.avatar }}" alt="avatar" width="40" height="40" class="avatar">
{%!e(MISSING)lse %!}(MISSING)
<span class="nav-link">Hello, {{ user.username }}</span>
{%!e(MISSING)ndif %!}(MISSING)
...
まとめ
python-social-authのパイプラインを利用して、アバター画像を引っ張ってこれるようになりました。やったね!