Django-Social-Auth错误

时间:2012-07-15 02:40:03

标签: django facebook django-socialauth

更新 我尝试使用以下内容替换自定义管理器中的所有内容:

def create_user(self, username, email):
        return self.model._default_manager.create(username=username)

这会引发错误。然后我尝试从我的自定义用户管理器返回用户,我得到“无法分配”“:”UserSocialAuth.user“必须是”Barbuser“实例。从associate_user抛出。它来自django.db.models.fields.related.py的内容。基本上,我知道如何从我的自定义模型mgr正确创建用户。我直接从文档引导我复制django内置的ModelManager中的所有内容。救命? 的更新

我在配置django-social-auth时遇到了问题。我已经在这里工作了3-4天,我已经准备好了。我安装了一个现有的用户注册应用程序,然后我安装并跟随django-social-auth github网站上的文档。我将以下内容添加到我的settings.py

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
    'polls',
    'barbuser',
    'social_auth',
)

AUTHENTICATION_BACKENDS = (
    'social_auth.backends.facebook.FacebookBackend',
    'django.contrib.auth.backends.ModelBackend',
)

FACEBOOK_APP_ID              = os.environ.get('FACEBOOK_APP_ID')
FACEBOOK_API_SECRET          = os.environ.get('FACEBOOK_SECRET')

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.contrib.auth.context_processors.auth',
    'social_auth.context_processors.social_auth_by_type_backends',
)

#SOCIAL_AUTH_ENABLED_BACKENDS = ('facebook',)
SOCIAL_AUTH_DEFAULT_USERNAME = 'new_social_auth_user'

LOGIN_URL          = '/login/'
LOGIN_REDIRECT_URL = '/profile/'
LOGIN_ERROR_URL    = '/login-error/'

SOCIAL_AUTH_USER_MODEL = 'barbuser.Barbuser'

我的models.py看起来像:

from datetime import date
from django.db import models
from django.contrib.auth.models import User
from django.db.models import BooleanField
from django.db.models.fields import DateTimeField
from django.utils import timezone
from django.utils.crypto import get_random_string

class BarbuserManager(models.Manager):
    @classmethod
    def normalize_email(cls, email):
        """
        Normalize the address by converting the domain part of the email address to lowercase.
        """
        email = email or ''
        try:
            email_name, domain_part = email.strip().rsplit('@', 1)
        except ValueError:
            pass
        else:
            email = '@'.join([email_name, domain_part.lower()])
            return email

    def create_user(self, username, email=None, password=None):
        """
        Creates and saves a User with the given username, email and password.
        """
        email = 'you@email.com' if email.strip() == '' else email
        now = timezone.now()
        if not username:
            raise ValueError('The given username must be set')
        email = BarbuserManager.normalize_email(email)
        user = User(username=username, email=email,
            is_staff=False, is_active=True, is_superuser=False,
            last_login=now, date_joined=now)
        user.set_password(password)
        user.save()
        barbuser = Barbuser(user=user, birthday=date.today(), last_login=user.last_login, name=username)
        barbuser.save()
        return barbuser

    def create_superuser(self, username, email, password):
        u = self.create_user(username, email, password)
        u.is_staff = True
        u.is_active = True
        u.is_superuser = True
        u.save(using=self._db)
        return u
    def make_random_password(self, length=10,
                             allowed_chars='abcdefghjkmnpqrstuvwxyz'
                                           'ABCDEFGHJKLMNPQRSTUVWXYZ'
                                           '23456789'):
        """        Generates a random password with the given length and given        allowed_chars. Note that the default value of allowed_chars does not        have "I" or "O" or letters and digits that look similar -- just to        avoid confusion.        """
        return get_random_string(length, allowed_chars)

    def get_by_natural_key(self, username):
        return self.get(username=username)

class Barbuser(models.Model):
    user = models.OneToOneField(User)
    username = models.CharField(max_length=200)
    last_login = DateTimeField(blank=True)
    is_active  = BooleanField(default=True)
    birthday = models.DateField()
    name = models.CharField(max_length=200)
    objects = BarbuserManager()

    def __init__(self, *args, **kwargs):
        me = super(Barbuser, self).__init__(*args, **kwargs)
        barbuser = me
        return me


    def __unicode__(self):
        return self.name

    def is_authenticated(self):
        return self.user.is_authenticated()

我已将我的urls.py更新为包含'social_auth.urls',并且在身份验证后,用户将从我的views.py重定向到ViewProfile视图:

# Create your views here.
from barbuser.forms import RegistrationForm, LoginForm
from barbuser.models import Barbuser
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template.context import RequestContext

def create_Barbuser(form):
    user = User.objects.create_user(form.cleaned_data['username'], form.cleaned_data['email'], form.cleaned_data['password'])
    user.save()
    barbuser = Barbuser(user=user, name=form.cleaned_data['name'], birthday=form.cleaned_data['birthday'])
    barbuser.save()


def process_form(form, request_context):
    if form.is_valid():
        create_Barbuser(form)
        return HttpResponseRedirect('/profile/')
    else:
        return render_to_response('register.html', {'form': form}, context_instance=request_context)


def render_blank_registration_form(request):
    '''When the user is not submitting the form, show them the blank registration form.'''
    form = RegistrationForm()
    context = {'form': form}
    return render_to_response('register.html', context, context_instance=RequestContext(request))


def BarbuserRegistration(request):
    """
    Handles the registration of new Barbwire users.
    """
    if request.user.is_authenticated():
        return HttpResponseRedirect('/profile/')
    if request.method == "POST":
        return process_form(RegistrationForm(request.POST), RequestContext(request))
    else:
        return render_blank_registration_form(request)

def LoginRequest(request):
    '''
    Handles Login requests.
    '''
    if request.user.is_authenticated():
        return HttpResponseRedirect('/profile/')
    if request.method == 'POST':
        form = LoginForm(request.POST)
        if form.is_valid():
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']
            barbuser = authenticate(username=username, password=password)
            if barbuser is not None:
                login(request, barbuser)
                return HttpResponseRedirect('/profile/')
            else:
                return render_to_response('login.html', {'form' : form}, context_instance=RequestContext(request))
        else:
            return render_to_response('login.html', {'form' : form}, context_instance=RequestContext(request))
    else:
        form = LoginForm()
        return render_to_response('login.html', {'form' : form}, context_instance=RequestContext(request))

def LoginError(request):
    return render_to_response('login.html', {'form' : LoginForm()}, context_instance=RequestContext(request))

def LogoutRequest(request):
    logout(request)
    return HttpResponseRedirect('/')

def ViewProfile(request):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/login/')
    else:
        return render_to_response('profile.html',{'barbuser' : request.user.barbuser }, context_instance=RequestContext(request))

我的问题是2倍。当我在models.py中添加这些额外的东西时:

def facebook_extra_values(sender, user, response, details, **kwargs):
    return False

from social_auth.signals import pre_update
from social_auth.backends.facebook import FacebookBackend

pre_update.connect(facebook_extra_values, sender=FacebookBackend)

我在服务器启动时出错:assert isinstance(to,basestring),“%s(%r)无效.OignanKey的第一个参数必须是模型,模型名称或字符串%r”%( self。 class ._ name _,to,RECURSIVE_RELATIONSHIP_CONSTANT) AssertionError:ForeignKey(None)无效。 ForeignKey的第一个参数必须是模型,模型名称或字符串'self'

当我删除它时,我可以通过Facebook流程登录,但我得到:AttributeError at / complete / facebook / 'NoneType'对象没有属性'extra_data'

我不确定我错过了什么或者我哪里出错了。有人可以帮我解释我哪里出错吗?

更新 我在调试中跟踪了这个问题,显然当我尝试“UserSocialAuth.objects.create”时,我在associate_user函数的social_auth.backends.pipeline.social.py中遇到了IntegrityError。然后它回退到一个调用social_auth_user()的Except块,这个函数为social_user返回None。我得到的IntegrityError是:

insert or update on table "social_auth_usersocialauth" violates foreign key constraint "social_auth_usersocialauth_user_id_fkey"
DETAIL:  Key (user_id)=(17) is not present in table "auth_user".

我不熟悉知道如何,在何处或为何将social_user与我在models.py中的CustomUserManager中创建的用户相关联。我还从models.py的底部删除了facebook_extra_values,额外的导入和preupdate.connect,因为我真的不明白它的作用或它的用途。我只是从示例应用程序中复制内容,尝试修复丢失关联的第一个问题。救命? 的更新

1 个答案:

答案 0 :(得分:4)

第一个问题 - ForeignKey错误 - 是由循环导入引起的。解决方案很简单,遵循惯例。将该信号注册到models.py末尾的代码块,并将其移动到名为barbuser/signals.py的新文件中。然后在barbuser/__init__.py中添加第from .signals import *

我没有运行你的代码足以得到你的第二个错误 - 'NoneType'对象没有属性'extra_data' - 但我发现了其他一些问题。

从settings.py中删除SOCIAL_AUTH_ENABLED_BACKENDS设置。我不确定你从哪里得到它,但它不在当前社会认证0.7.0的文档中。它也不在social_auth代码中。可能是一个古老的环境。

您在settings.py(social_auth_login_redirect)中引用了不存在的上下文处理器。再一次,也许是一个旧功能。确保您运行的是最新的社交身份验证(通过PyPi与pip install django-social-auth一起提供)。此外,只使用您需要的上下文处理器,永远不会全部。 (上下文处理器将变量添加到模板上下文中。如果您未在模板中使用social_auth变量,则不需要任何社交身份验证上下文处理器。)这很重要,因为有两个处理器相互冲突。来自documentation

  

social_auth_backends和social_auth_by_type_backends玩得不好   在一起。

确保您已运行./manage.py syncdb为社交身份验证模型设置数据库。如果模型没有数据库表,则会导致“UserSocialAuth.objects.create()”中断。

最后想到,Django不喜欢你在定义自己的用户模型时所做的事情。最好单独留下auth.User并制作UserProfile

更新

检查数据库结构;我怀疑索引是不正确的。更好的是,只需删除三个social_auth_*表和syncdb。 UserSocialAuth表具有用户模型的ForeignKey约束。它应该将“user_id”映射到“Barbuser.id”,但如果在设置settings.py/SOCIAL_AUTH_USER_MODEL值之前创建了表,那么表将永远被破坏,因为当初始SQL是最初的SQL时,SocialAuth默认为Django的Auth.User跑。合理?无论如何,只需在配置了社交身份验证后重新创建表。

注意:您最近使用self.model._default_manager.create()的实验未完成任何操作。 “self”是一个BarbuserManager; “模特”是巴布瑟; “_default_manager”返回BarbuserManager。为什么? “Barbuser.objects”模型的默认管理器。

哦,你第一次纠正了。 BarbuserManager.create_user()需要返回Barbuser。