首页 > 解决方案 > /social/complete/facebook/ 处的 social_django TypeError 需要一个类似字节的对象,而不是“元组”

问题描述

我正在使用 social_django 进行 Facebook 登录。当用户使用 facebook 登录时,我想拥有 facebook 的个人资料照片。但是,当我尝试使用 facebook 登录时出现此错误;

/social/complete/facebook/a 字节类对象的类型错误是必需的,而不是“元组”

我已经设法将图片(Facebook 给我的 url 作为回应)下载到我的 media/profile_pics 文件夹,但我无法将它保存到该人的个人资料图片中。我认为问题来自 ImageField 和 FileField 困境,但我无法解决。

我在网上尝试了许多解决方案,但没有帮助。感谢您在高级方面的任何帮助。

设置.py

#social_django
AUTHENTICATION_BACKENDS = (
    'social_core.backends.github.GithubOAuth2', #github
    'social_core.backends.twitter.TwitterOAuth', #twitter
    'social_core.backends.facebook.FacebookOAuth2', #facebook
    'django.contrib.auth.backends.ModelBackend', #default django backend

    # For Google Authentication
    'social.backends.google.GoogleOpenId',
    'social.backends.google.GoogleOAuth2',
    'social.backends.google.GoogleOAuth',

    'apps.users.backend.EmailOrUsernameModelBackend', # loging with email or username
)

#social_django
SOCIAL_AUTH_FACEBOOK_KEY = '*****************'  # App ID
SOCIAL_AUTH_FACEBOOK_SECRET = '***************'  # App Secret
SOCIAL_AUTH_FACEBOOK_SCOPE = [
'email' ,
'user_location',
'user_hometown',
'user_birthday', 
'user_friends', 
'public_profile', 
]
SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = {
    'fields': 'id,name,email, gender, birthday, link, location, hometown, first_name, last_name, picture'
}
SOCIAL_AUTH_ADMIN_USER_SEARCH_FIELDS = ['username', 'first_name', 'email']

#social_django
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',
    'apps.users.pipeline.save_account',
    'apps.users.pipeline.save_profile_picture',
)

#social_django
SOCIAL_AUTH_STRATEGY = 'social_django.strategy.DjangoStrategy'
SOCIAL_AUTH_STORAGE = 'social_django.models.DjangoStorage'

模型.py

class Account(AbstractBaseUser):  
    email               = models.EmailField(max_length=60, unique=True)
    username            = models.CharField(max_length=30, unique=True)

    date_joined         = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
    last_login          = models.DateTimeField(verbose_name='last_login', auto_now=True)
    is_admin            = models.BooleanField(default=False)
    is_active           = models.BooleanField(default=True)
    is_staff            = models.BooleanField(default=False)
    is_superuser        = models.BooleanField(default=False)

    company             = models.CharField(default='', max_length=200, help_text='In order to share the application with other users; you need to provide a valid company information', blank=True, null=True)
    phone               = PhoneNumberField('Phone Number', default='', help_text='Kindly use the global formatting without spaces (+90 531 531 53 53 = +905315315353)', unique=True, blank=True, null=True)
    first_name          = models.CharField(max_length=100, blank=True, null=True)
    last_name           = models.CharField(max_length=100, blank=True, null=True)
    GENDER_LIST=(
        ('Male', 'Male'),
        ('Female', 'Female')
        )
    gender              = models.CharField(max_length=100, choices=GENDER_LIST, blank=True, null=True) 
    birthday            = models.DateField(help_text='Kindly provide a global date formatting as follows: (YYYY-MM-DD)', auto_now=False, blank=True, null=True)
    country             = models.ForeignKey(Country, on_delete=models.SET_NULL,  blank=True, null=True)
    city                = models.ForeignKey(City, on_delete=models.SET_NULL,  blank=True, null=True)
    district            = models.CharField(max_length=100, blank=True, null=True)
    image               = models.ImageField(default='default.jpg', upload_to='profile_pics')
    slug                = models.SlugField(max_length=200, blank=True, null=True) 

    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = [] #username and password are required by default

    objects = AccountManager() # tells this Account database that; the manager database which is in the top AccountManager

    def __str__(self):  
        return f'{self.email}'  

    def has_perm(self, perm, obj=None): # has permissions; if user is an admin; he can change stuff in the database 
        return self.is_admin

    def has_module_perms(self, app_label): # has module permissions;  
        return True
        # return self.is_admin

    def get_absolute_url(self):
        return reverse('account_detailview', kwargs={'pk': self.pk})

    def save(self, *args, **kwargs):  
        super().save(*args, **kwargs)  

        img = Image.open(self.image.path)  
        if img.height > 300 or img.width > 300: 
            output_size = (300, 300) 
            img.thumbnail(output_size) 
            img.save(self.image.path)

    def email_user(self, subject, message, from_email=None): #Sends an email to this User.
        send_mail(subject, message, from_email, [self.email])

管道.py

from requests import request, HTTPError
from django.core.files.base import ContentFile
import urllib.request
from urllib.request import urlopen
import os
from django.core.files import File

def save_profile_picture(backend, user, response, details, *args,**kwargs):
    account = Account.objects.filter(email=response['email']).first()

    if backend.name == 'facebook':
        url = response['picture']['data']['url']
        os.chdir('media/profile_pics')

        # if url:
        #     avatar = urlopen(url).read()
        #     fout = open(account.username+'.jpg', "wb") #filepath is where to save the image
        #     fout.write(avatar)
        #     fout.close()
        #     # account.image = url_to_image # depends on where you saved it
        #     # account.save()

        downloaded_pic = urllib.request.urlretrieve(url, account.username + ".jpg")
        print("TYPE OF PICTURE --------------------------------------------------------")
        print(type(downloaded_pic))
        account.image.save(account.username + ".jpg", ContentFile(downloaded_pic))
        account.save()

有所有的追溯

TypeError at /social/complete/facebook/
a bytes-like object is required, not 'tuple'
Request Method: GET
Request URL:    http://localhost:8000/social/complete/facebook/?granted_scopes=user_birthday%2Cuser_hometown%2Cuser_location%2Cuser_friends%2Cemail%2Cpublic_profile&denied_scopes&code=AQD8CNhL-JVKC41Go2Vy65rRMMo3EnKWdsgwOa8idyKsgYFLPKVHL3r7pkOSjWzl_b_GCr9-vhPpAWrxgYgIFHwILStxfaA3KgoX5VU6pfdnukk0D1RgoQaVvaAA0DLbqJ479srSeXEDLgWvqQ3X9Ndqs-0smd1ClclWkz1SnQJ8jqCEPq2YrFH4yqCBgCy5tJs1Xqyjd494VrcEsYZ_NkcLdzIUFQRDpGkttz4yRDc3wkzMG67uJefBexAJomGiwTb8XSdGwdtB2koQsfX8gxcAh8eYZBxVmjGDgTV5lEiP_6-d6NH0S8vd0kKiSDDUtpU&state=ORXsv8aaTqk11W1DGNJ6bD8VzGysexDX
Django Version: 3.0.6
Exception Type: TypeError
Exception Value:    
a bytes-like object is required, not 'tuple'
Exception Location: C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\django\core\files\base.py in __init__, line 127
Python Executable:  C:\Users\semih\AppData\Local\Programs\Python\Python38\python.exe
Python Version: 3.8.2
Python Path:    
['D:\\SEMİH\\Programming\\Python\\Works\\django norga_asistant deneme 2',
 'C:\\Users\\semih\\AppData\\Local\\Programs\\Python\\Python38\\python38.zip',
 'C:\\Users\\semih\\AppData\\Local\\Programs\\Python\\Python38\\DLLs',
 'C:\\Users\\semih\\AppData\\Local\\Programs\\Python\\Python38\\lib',
 'C:\\Users\\semih\\AppData\\Local\\Programs\\Python\\Python38',
 'C:\\Users\\semih\\AppData\\Local\\Programs\\Python\\Python38\\lib\\site-packages']
Server time:    Fri, 5 Mar 2021 11:08:21 +0000
Traceback Switch to copy-and-paste view
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\django\core\handlers\exception.py in inner
            response = get_response(request) …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\django\core\handlers\base.py in _get_response
                response = self.process_exception_by_middleware(e, request) …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\django\core\handlers\base.py in _get_response
                response = wrapped_callback(request, *callback_args, **callback_kwargs) …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\django\views\decorators\cache.py in _wrapped_view_func
        response = view_func(request, *args, **kwargs) …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\django\views\decorators\csrf.py in wrapped_view
        return view_func(*args, **kwargs) …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\social_django\utils.py in wrapper
            return func(request, backend, *args, **kwargs) …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\social_django\views.py in complete
    return do_complete(request.backend, _do_login, user=request.user, …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\social_core\actions.py in do_complete
        user = backend.complete(user=user, *args, **kwargs) …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\social_core\backends\base.py in complete
        return self.auth_complete(*args, **kwargs) …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\social_core\utils.py in wrapper
            return func(*args, **kwargs) …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\social_core\backends\facebook.py in auth_complete
        return self.do_auth(access_token, response, *args, **kwargs) …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\social_core\backends\facebook.py in do_auth
        return self.strategy.authenticate(*args, **kwargs) …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\social_django\strategy.py in authenticate
        return authenticate(*args, **kwargs) …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\django\contrib\auth\__init__.py in authenticate
            user = backend.authenticate(request, **credentials) …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\social_core\backends\base.py in authenticate
        return self.pipeline(pipeline, *args, **kwargs) …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\social_core\backends\base.py in pipeline
        out = self.run_pipeline(pipeline, pipeline_index, *args, **kwargs) …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\social_core\backends\base.py in run_pipeline
            result = func(*args, **out) or {} …
▶ Local vars
D:\SEMİH\Programming\Python\Works\django norga_asistant deneme 2\apps\users\pipeline.py in save_profile_picture
        account.image.save(account.username + ".jpg", ContentFile(downloaded_pic)) …
▶ Local vars
C:\Users\semih\AppData\Local\Programs\Python\Python38\lib\site-packages\django\core\files\base.py in __init__
        super().__init__(stream_class(content), name=name) …
▶ Local vars

标签: pythondjangoimageauthentication

解决方案


问题是urlretrieve()它返回一个 (filename, headers) 的元组,因此您需要将返回值分配给一个元组,如下所示:

downloaded_pic, headers = urllib.request.urlretrieve(url, account.username + ".jpg")

即使您不会使用headers. 这类似于许多人在使用 Django 时遇到的问题Model.objects.get_or_create(...),它返回 (instance, created) 的一个元组。

请参阅urllib 文档


推荐阅读