python-social-authでプロフィール画像の保存
はじめに
python-social-authでOauth認証した際に、プロフィール画像を保存したかったのでpipelineを追加してみました。
環境
requirements.txt
Django==1.5.12 python-social-auth==0.2.13
まず画像を扱えるようにする
ImageFieldを扱えるように
models.ImageFiledを利用して画像を保存したいので、まずはその準備。
モデルフィールドリファレンス — Django 1.4 documentationによると、 Python Imaging Libraryが必要らしい。
pipでインストールする場合は、
$ pip install Pillow
MEDIA_ROOTとか
settings.py
import os # ./ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # ./media MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
注意
自身の環境に合わせて変更してください。
これでとりあえず画像が扱えます。
CustomUserを定義
settings.py
SOCIAL_AUTH_USER_MODEL = 'app.CustomUser'
models.py
from django.contrib.auth.models import AbstractUser, UserManager from django.db import models class CustomUser(AbstractUser): class Meta: app_label = 'app' # profile_picture_urlは別に無くてもいい profile_picture_url = models.URLField() # upload_toでprofilesを指定 # 今回の場合./media/profilesになる profile_picture = models.ImageField(upload_to='profiles') objects = UserManager() def __unicode__(self): return self.username
CustomUserにImageFieldを持たせて、upload_to='path'で画像の保存先を指定。
pipelineを作る
まずは設定から
自分でpipelineを足す場合は、デフォルト + 自作pipelineにしないと正常に認証処理が通らない。
settings.py
SOCIAL_AUTH_PIPELINE = ( 'social.pipeline.social_auth.social_details', 'social.pipeline.social_auth.social_uid', 'social.pipeline.social_auth.auth_allowed', 'social.pipeline.social_auth.social_user', 'social.pipeline.user.get_username', # 'social.pipeline.mail.mail_validation', # 'social.pipeline.social_auth.associate_by_email', 'social.pipeline.user.create_user', 'social.pipeline.social_auth.associate_user', 'social.pipeline.social_auth.load_extra_data', 'social.pipeline.user.user_details', # 'social.pipeline.debug.debug', # ここから上はデフォルトなので必須 # save_profile_pictureがこれから作るpipeline 'app.pipeline.save_profile_picture',
pipelineを作る
SOCIAL_AUTH_PIPELINEで指定した場所に、pipelineを作る。
今回だと、./app/pipeline.py
pipeline.py
import os from urllib2 import urlopen from django.core.files.base import ContentFile import settings def save_profile_picture(backend, strategy, details, response ,user=None, *args, **kwargs): url = None if backend.name == 'google-oauth2': # 画像のurlを保存 url = response['image'].get('url') # 拡張子を用意 ext = url.split('.')[-1].split('?')[0] if url: user.profile_picture_url = url picture = os.path.join(settings.MEDIA_ROOT, 'profiles', '%s.%s' % (user.username, ext)) # 既にプロフィール画像がある場合、削除 if os.path.exists(picture): os.remove(picture) user.profile_picture.save('%s.%s' % (user.username, ext), ContentFile(urlopen(url).read())) user.save()
save_profile_pictureの解説
urlが、
https://………/photo.jpg?sz=50
となってたので、urlにsplit()を2回当てて、拡張子のみを取得。
./media/profiles/にusername.jpgとして保存するのだが、
ImageFieldは既に画像が存在した場合、
suffixが付きの別画像として保存されてしまう。
だから、プロフィール画像が既に存在する場合は削除してから、保存させる。
注意
今回はGoogleOauth2の場合。
twitterとかgithubを足したいなら、if文を追加。
おわりに
最初からプロフィール画像を保存するようにしてくれればいいのに…
と思って時期が私にもありました。