django-allauth: проверьте, зарегистрировался ли пользователь, используя социальную учетную запись
Поэтому я включил в свое приложение django-allauth, и теперь пользователи имеют возможность входить в систему через Instagram. Допустим, у меня есть модель с именем UserProfile, и у нее есть поле
user_avatar = models.ImageField(upload_to='profile_images', blank=True, default=None)
И с этим у меня есть сигнал, который создает профиль пользователя, как только новый пользователь регистрируется:
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
Так, обычно, когда пользователь регистрирует user_avatar, является пустым, так как значение по умолчанию установлено как None, теперь я хочу добавить в сигнал (если это правильный способ сделать это), чтобы проверить, создал ли пользователь свою учетную запись, войдя в систему, используя instagram., чтобы пойти и получить свою фотографию профиля и использовать его в user_avatar. Я думаю, что это возможно https://instagram.com/developer/endpoints/users/, но так как я полный нуб в python и django, я не знаю, как именно это сделать.
Так что я нашел этот сигнал из документов Джанго-Аллаута allauth.socialaccount.signals.pre_social_login(request, social_login)
так что это говорит о том, что я могу проверить, что пользователь зарегистрировался, используя социальную учетную запись, но как бы я использовал это с моей функцией create_user_profile? Шаги, о которых я подумал, - это сначала создать профиль, который я сделал, а затем проверить, зарегистрировался ли пользователь, используя социальную учетную запись, или нет, если он это сделал, то user_avatar, который использует свое изображение профиля instagram, и если нет, то останется как никто.
И как плюс, я знаю, что могу получить изображение профиля социальной учетной записи пользователя в шаблоне, используя {{user.socialaccount_set.all.0.get_avatar_url}}
, но я не хочу делать это с помощью шаблонов, а не делать это с помощью моделей, что является лучшим способом.
Это может выглядеть очень глупо, но я попробовал и попытался что-то придумать (это то, что, как думает новичок, сработает, я думал об этом на макушке, так как понятия не имею, работают ли такие сигналы)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
def pre_social_login(request, social_login):
user_logged_social = social_login.account.user
if user_logged_social:
UserProfile.objects.get(user_avatar=user_logged_social.profile_picture)
else:
pass
post_save.connect(create_user_profile, sender=User)
ОБНОВЛЕНИЕ Работает с помощью @bellum! Спасибо!
Вот код, который я использовал:
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name="profile")
user_avatar = models.ImageField(upload_to='profile_images'
blank=True,
default=None)
def __unicode__(self):
return self.user.username
class Meta:
verbose_name_plural = "User Profiles"
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
3utils.py
def download_file_from_url(url):
# Stream the image from the url
try:
request = requests.get(url, stream=True)
except requests.exceptions.RequestException as e:
# TODO: log error here
return None
if request.status_code != requests.codes.ok:
# TODO: log error here
return None
# Create a temporary file
lf = tempfile.NamedTemporaryFile()
# Read the streamed image in sections
for block in request.iter_content(1024 * 8):
# If no more file then stop
if not block:
break
# Write image block to temporary file
lf.write(block)
return files.File(lf)
class SocialAccountAdapter(DefaultSocialAccountAdapter):
def save_user(self, request, sociallogin, form=None):
user = super(SocialAccountAdapter, self).save_user(request, sociallogin, form)
url = sociallogin.account.get_avatar_url()
avatar = download_file_from_url(url)
if avatar:
profile = user.profile # access your profile from user by correct name
profile.user_avatar.save('avatar%d.jpg' % user.pk, avatar)
return user
settings.py
SOCIALACCOUNT_ADAPTER = 'main.s3utils.SocialAccountAdapter'
Сигнал для создания профиля при регистрации в моих моделях остался прежним, просто добавили SocialAccountAdapter!
1 ответ
Я сделал ту же задачу для Facebook
поставщик. allauth
дает возможность достичь этого по-другому. Я думаю, вам не нужно получать аватар каждый раз, когда пользователь входит в вашу систему. Если да, то вы можете переопределить класс следующим образом:
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
class SocialAccountAdapter(DefaultSocialAccountAdapter):
def save_user(self, request, sociallogin, form=None):
user = super(SocialAccountAdapter, self).save_user(request, sociallogin, form)
url = sociallogin.account.get_avatar_url()
avatar = download_file_from_url(url) # here you should download file from provided url, the code is below
if avatar:
profile = user.user_profile # access your profile from user by correct name
profile.user_avatar.save('avatar%d.jpg' % user.pk, avatar)
return user
Вы должны добавить эту строку в вашу конфигурацию: SOCIALACCOUNT_ADAPTER = 'path-to-your-adapter.SocialAccountAdapter'
,
В результате этот код будет вызываться только во время регистрации нового социального аккаунта, получить URL-адрес аватара, загрузить его и сохранить в своем User
модель.
import requests
import tempfile
from django.core import files
def download_file_from_url(url):
# Stream the image from the url
try:
request = requests.get(url, stream=True)
except requests.exceptions.RequestException as e:
# TODO: log error here
return None
if request.status_code != requests.codes.ok:
# TODO: log error here
return None
# Create a temporary file
lf = tempfile.NamedTemporaryFile()
# Read the streamed image in sections
for block in request.iter_content(1024 * 8):
# If no more file then stop
if not block:
break
# Write image block to temporary file
lf.write(block)
return files.File(lf)