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の腸から来ています。基本的に、カスタムモデルマネージャーからユーザーを正しく作成する方法を知ることに固執しています。私はドキュメントから直接離れていたので、ModelManagerに組み込まれているdjangoからすべてをコピーすることになりました。ヘルプ? アップデート

django-social-authの設定に問題があります。私はこれに3〜4日間いて、タオルを投げる準備をしています。動作する既存のユーザー登録アプリをインストールしてから、django-social-authgithubサイトのドキュメントをインストールしてフォローしました。私は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/のAttributeError'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で作成されたユーザーに関連付ける方法、場所、または理由を十分に理解していません。また、facebook_extra_values、追加のインポート、preupdate.connectのものをmodels.pyの下部から削除しました。これは、それが何をするのか、何のためにあるのかが本当にわからないためです。関連付けが欠落しているという最初の問題を修正しようとして、サンプルアプリから物事をコピーしただけでした。ヘルプ? アップデート

4

1 に答える 1

4

最初の問題であるForeignKeyエラーは、循環インポートが原因で発生します。解決策は簡単で、慣例に従います。models.pyの最後にあるシグナル登録コードブロックを取得し、。という名前の新しいファイルに移動しますbarbuser/signals.py。次にbarbuser/__init__.py、行を入れて、from .signals import *

2番目のエラー(「NoneType」オブジェクトには属性「extra_data」がありません)を取得するのに十分なコードを実行していませんが、他にもいくつか問題が見つかりました。

SOCIAL_AUTH_ENABLED_BACKENDSsettings.pyから設定を削除します。どこから入手したかはわかりませんが、現在のsocial-auth0.7.0のドキュメントにはありません。それはsocial_authコードにもありません。おそらく古い設定です。

settings.py()で存在しないコンテキストプロセッサを参照しますsocial_auth_login_redirect。繰り返しますが、おそらく古い関数です。最新のsocial-auth(を使用してPyPiから入手可能)を実行していることを確認してくださいpip install django-social-auth。また、必要なコンテキストプロセッサのみを使用し、すべてを使用することはできません。(コンテキストプロセッサは、テンプレートコンテキストに変数を追加します。テンプレートでsocial_auth変数を使用していない場合は、social-authコンテキストプロセッサは必要ありません。)2つのプロセッサが互いに競合するため、これは重要です。ドキュメントから、

social_auth_backendsとsocial_auth_by_type_backendsは一緒にうまく機能しません。

./manage.py syncdb実行して、social-authモデルのデータベースをセットアップしたことを確認してください。モデルのデータベーステーブルがない場合、「UserSocialAuth.objects.create()」が機能しなくなります。

最後に考えたのは、Djangoは、独自のユーザーモデルを定義するために行っているタイプのことを好まないということです。auth.Userをそのままにして、UserProfileを作成することをお勧めします。

アップデート

データベース構造を確認してください。インデックスが正しくないのではないかと思います。さらに良いことに、3つのsocial_auth_*テーブルを削除してからsyncdbもう一度削除してください。UserSocialAuthテーブルには、ユーザーモデルに対するForeignKey制約があります。「user_id」を「Barbuser.id」にマッピングする必要がありますが、settings.py/SOCIAL_AUTH_USER_MODEL値を設定する前にテーブルが作成された場合、最初のSQLの実行時にSocialAuthがデフォルトでDjangoのAuth.Userに設定されたため、テーブルは永久に壊れます。わかる?とにかく、Social Authを構成したので、テーブルを再作成するだけです。

注:を使用した最近の実験self.model._default_manager.create()では、何も達成されていません。「自己」はBarbuserManagerです。「モデル」はBarbuserです。「_default_manager」がBarbuserManagerに戻ります。なんで?「Barbuser.objects」、モデルのデフォルトのマネージャーです。

ああ、あなたはそれを最初に修正しました。BarbuserManager.create_user()はBarbuserを返す必要があります。

于 2012-07-16T03:46:25.983 に答える