2

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

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 的内部。基本上,我坚持知道如何从我的自定义模型经理中正确创建用户。我直接离开了导致我从 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) is invalid. ForeignKey 的第一个参数必须是模型、模型名称或字符串 %r" % ( self.class ._ name _, to, RECURSIVE_RELATIONSHIP_CONSTANT) AssertionError: ForeignKey(None) 无效。ForeignKey 的第一个参数必须是模型、模型名称或字符串“self”

当我删除它时,我可以通过 facebook 流程登录,但我得到:/complete/facebook/ 'NoneType' 对象的 AttributeError 没有属性 '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 内容,因为我真的不明白它的作用或用途。我只是从示例应用程序中复制东西,试图解决我的第一个问题,即缺少关联。帮助? 更新

4

1 回答 1

4

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

我还没有运行足够远的代码来得到你的第二个错误——“NoneType”对象没有属性“extra_data”——但我发现了其他几个问题。

从 settings.py 中删除SOCIAL_AUTH_ENABLED_BACKENDS设置。我不确定你是从哪里得到的,但它不在当前 social-auth 0.7.0 的文档中。它也不在 social_auth 代码中。应该是老环境了。

social_auth_login_redirect您在 settings.py ( )中引用了一个不存在的上下文处理器。同样,也许是一个旧功能。确保您正在运行最新的 social-auth(可通过 PyPi 使用pip install django-social-auth)。此外,仅使用您需要的上下文处理器,而不是全部使用。(上下文处理器将变量添加到模板上下文中。如果您没有social_auth在模板中使用该变量,那么您不需要任何社交身份验证上下文处理器。)这很重要,因为其中两个处理器相互冲突。从文档中,

social_auth_backends 和 social_auth_by_type_backends 不能一起玩。

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

最后一个想法,Django 不喜欢你定义自己的用户模型所做的事情。最好不要管 auth.User 并创建一个UserProfile

更新

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

注意:您最近使用self.model._default_manager.create()的实验没有完成任何事情。“self”是一个 BarbuserManager;“模型”是 Barbuser;“_default_manager”又回到了 BarbuserManager。为什么?“Barbuser.objects”模型的默认管理器。

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

于 2012-07-16T03:46:25.983 回答