如何在django-allauth首次社交登录后强制填写用户个人资料?

时间:2016-02-24 20:50:38

标签: django django-models django-allauth

我在我的应用程序中创建了UserProfile模型:

class UserProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL,
                                on_delete=models.CASCADE,
                                primary_key=True,
                                verbose_name=_('user'),
                                related_name='user_profile')
    locality = models.CharField(max_length=85)
    voivodship = models.CharField(max_length=20,
                                  choices=Vovoidship.choices,
                                  validators=[Vovoidship.validator])
    postcode = models.IntegerField()
    street = models.CharField(max_length=75)
    building = models.SmallIntegerField()
    premises = models.CharField(max_length=80)
    phonenumber = PhoneNumberField(blank=True)

    @staticmethod
    def post_save_create(sender, instance, created, **kwargs):
        if created:
            profile, created = UserProfile.objects.get_or_create(user=instance)

post_save.connect(UserProfile.post_save_create, sender=User)

现在,我陷入了自己的陷阱。我不想放松约束并在数据库中保留需要填充地址字段的要求。我正在使用django-allauth。使用设置ACCOUNT_SIGNUP_FORM_CLASS = 'management.forms.SignupForm'解决了传统注册表单的问题,如果用户首次使用社交帐户登录,则出于明显原因我遇到了约束违规:

IntegrityError at /accounts/google/login/callback/
null value in column "postcode" violates not-null constraint
DETAIL:  Failing row contains (4, , , null, , null, , ).

因此,问题是,如何正确实现填写应用程序UserProfile中字段信息的请求?令我感到惊讶的是django-allauth没有像ACCOUNT_SIGNUP_FORM_CLASS一样处理内置处理程序。

当我对Django new 时,请假设我不知道一些事情,而不是显而易见的事情。感谢。

2 个答案:

答案 0 :(得分:0)

我认为你需要:

1.-创建自定义注册类,以便您执行其他工作

class SignupForm(forms.Form):
    locality = forms.CharField(max_length=85)
    voivodship = forms.CharField(max_length=20)
    postcode = forms.IntegerField()
    etc.

    def signup(self, request, user):
        # I think the profile will exist at this point based on
        # your post_save_create. But if not, just create it here
        if user.user_profile:
             user.user_profile.locality = self.cleaned_data['locality']
             user.user_profile.voivodship = self.cleaned_data['voivodship']
             user.user_profile.postcode = self.cleaned_data['postcode']
             ...
             user.user_profile.save()    

2.-设置ACCOUNT_SIGNUP_FORM_CLASS = 'yourproject.yourapp.forms.SignupForm'让allauth使用您的表单

3.-设置SOCIALACCOUNT_AUTO_SIGNUP=False以确保即使使用社交注册也可以显示表单。

答案 1 :(得分:0)

davka有一些功劳,我已经设法形成了一个有效的解决方案,需要在UserProfile类的signup()方法中创建SignupForm对象,但由于数据库的原因/ model约束它必须在创建期间填充数据 。结果:

class SignupForm(ModelForm):
    first_name = CharField()
    last_name = CharField()

    class Meta:
        model = UserProfile
        exclude = ['user', 'phonenumber']

    def signup(self, request, user):
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        profile, created = UserProfile.objects.get_or_create(
            user=user, defaults={
                'locality': self.cleaned_data['locality'],
                'voivodship': self.cleaned_data['voivodship'],
                'postcode': self.cleaned_data['postcode'],
                'street': self.cleaned_data['street'],
                'building': self.cleaned_data['building'],
                'premises': self.cleaned_data['premises'],
            })
        if created: # This prevents saving if profile already exist
            profile.save()

该解决方案并不完全符合DRY原则,但显示了这一想法。更进一步,它可能会迭代匹配模型字段的结果。

需要在settings.py中正确设置两个元素:

  • ACCOUNT_SIGNUP_FORM_CLASS = 'yourapp.forms.SignupForm'allauth
  • 中启用此表单
  • SOCIALACCOUNT_AUTO_SIGNUP = False这 - 与直觉相反 - 让allauth在完成注册之前显示表单如果用户选择社交登录但没有帐户;如果帐户已经存在(用户名和/或电子邮件地址取决于其他设置),它可以安全地工作,因为不允许完成注册(为什么他们称之为注册?)和用户被迫登录并链接社交帐户。