django-allauth:检查用户是否使用社交帐户注册

django-allauth: Check whether user signed up using a social account

所以我在我的应用程序中集成了 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 的完全菜鸟,所以我不知道该怎么做。

所以我从 django-allauth 文档中找到了这个信号 allauth.socialaccount.signals.pre_social_login(request, social_login) 所以这说明我可以检查用户是否已经使用社交帐户注册,但是我如何将它与我的 create_user_profile 功能?我想到的步骤是首先创建我所做的个人资料,然后检查用户是否使用社交帐户注册,如果他们这样做,那么 user_avatar 使用他们的 instagram 个人资料图片,如果没有它会保持 none.

另外,我知道我可以使用 {{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!

我已经为 Facebook 提供商完成了相同的任务。 allauth 提供了以另一种方式实现这一目标的可能性。我认为您不需要每次用户登录您的系统时都获得头像。如果是,那么您可以像这样覆盖 class:

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)