微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Django-allauth - 使用 OneToOneField 自定义注册

如何解决Django-allauth - 使用 OneToOneField 自定义注册

我创建了一个 sign up form using two grouped forms 并且它一直工作得很好,但我想使用 django-allauth 因为它的功能(仅使用电子邮件登录,发送确认电子邮件......)。 然而,即使阅读了一些主题,我仍然无法阅读。

forms.py

class ExtendedUserCreationForm(UserCreationForm):
    email = forms.EmailField(required=True,label="E-mail")
    first_name = forms.CharField(max_length=30,label="Nome")
    last_name = forms.CharField(max_length=30,label="Sobrenome")


    class Meta:
        model = User
        fields = ('first_name','last_name','username','email','password1','password2')


    def save(self,commit=True):
        user = super().save(commit=False)

        user.email = self.cleaned_data['email']
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']

        if commit:
            user.save()
        return user


class UserProfileForm(forms.ModelForm):
    class Meta:
        model = UserProfile
        fields = ('sexo','data_nascimento','foto','sobre_mim','telefone','paroquia','cidade','estado','cep','possui_filhos','facebook','instagram')
        CIDADES = []
        for i in cidadesReader:
            if i[1] not in CIDADES:
                CIDADES.append(i[1])
        widgets = {            
            'cidade': floppyforms.widgets.Input(datalist=CIDADES,attrs={'autocomplete': 'off'}),}

views.py

def signup(request):
    if request.method == 'POST':
        form = ExtendedUserCreationForm(request.POST)
        profile_form = UserProfileForm(request.POST,request.FILES)

        if form.is_valid() and profile_form.is_valid():

            user = form.save()

            profile = profile_form.save(commit=False)
            profile.user = user


            profile.save()

            username = form.cleaned_data.get('username')
            password = form.cleaned_data.get('password1')
            user = authenticate(username=username,password=password)
            #login(request,user)
            return redirect('home')
    else:
        form = ExtendedUserCreationForm()
        profile_form = UserProfileForm()

    context = {'form': form,'profile_form' : profile_form}
    return render(request,'registration/signup.html',context)

signup.html

{% extends '_base.html' %}

{% load crispy_forms_tags %}

{% block title %}Cadastrar{% endblock title %}

{% block content %}

<h2>Criar Perfil</h2>
<form novalidate method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form|crispy }}
    {{ profile_form|crispy }}
    <button class="btn btn-success" type="submit">Cadastrar</button>
</form>
{% endblock content %}

models.py

class UserProfile(models.Model):
        user = models.OnetoOneField(User,on_delete=models.CASCADE)    
    
    
        SEXOS = (
            ('M','Masculino'),('F','Feminino'),)
        sexo = models.CharField(max_length=1,choices=SEXOS)
        data_nascimento = models.DateField(validators=[idade_minima])    
        ...

我尝试使用 settings.py 中的 ACCOUNT_SIGNUP_FORM_CLASSACCOUNT_FORMS 选项,但没有用。

我尝试进行一些调整,如本主题中与我的问题类似: Django allauth saving custom user profile fields with signup form

例如,我在 models.py 中更改了它,并且我做了迁移

user = models.OnetoOneField(User,on_delete=models.CASCADE,unique=True,related_name ='profile')

多次尝试后,最常见的错误是:

RelatedobjectDoesNotExist at /accounts/signup/

User has no profile.

编辑:

我更改了 UserProfile 中的 slug,因为它取决于用户(名字)。错误已更改:

IntegrityError at /accounts/signup/

NOT NULL constraint Failed: profiles_userprofile.user_id

但是UserProfile没有用户在决赛中继续。 (在 settings.py 中使用:ACCOUNT_SIGNUP_FORM_CLASS = 'profiles.forms.UserProfileForm'。来自回溯的详细信息:

...lib/python3.6/site-packages/allauth/account/views.py in dispatch
215 return super(SignupView,self).dispatch(request,*args,**kwargs)

.../lib/python3.6/site-packages/allauth/account/views.py in post
104 response = self.form_valid(form)

...lib/python3.6/site-packages/allauth/account/views.py in form_valid
231 self.user = form.save(self.request)

...lib/python3.6/site-packages/allauth/account/forms.py in save
405 self.custom_signup(request,user)

...lib/python3.6/site-packages/allauth/account/forms.py in custom_signup
359 custom_form.save(user)

...profiles/models.py in save
super(UserProfile,self).save(*args,**kwargs)

 ▼ Local vars
Variable    Value
__class__   

<class 'profiles.models.UserProfile'>

args    ()
kwargs  {}
self    Error in formatting: RelatedobjectDoesNotExist: UserProfile has no user.
slug_name   'nome-sp-260221205510' 

信号

使用信号错误发生了变化。我在 models.py添加了它:

@receiver(post_save,sender=User)
def create_user_profile(sender,instance,created,**kwargs):
    if created:
        UserProfile.objects.create(user=instance)

错误

ValueError at /accounts/signup/
The 'foto' attribute has no file associated with it.

然后我尝试删除 foto 字段,但另一个错误发生在另一个字段中:

IntegrityError at /accounts/signup/
NOT NULL constraint Failed: profiles_userprofile.data_nascimento

在此先感谢您的帮助。

解决方法

错误 UserProfile has no userUserProfile.save() 中触发。您第一次在视图中使用 commit=False 调用它,然后才设置用户:

# your code from the question

        profile = profile_form.save(commit=False)
        profile.user = user
        profile.save()

我猜 UserProfile.save 会读取 user 字段来创建 slug。如果 commit=False,您可以跳过它,或者如果您像这样更改它,它可能已经可以工作了:

profile_form.instance.user = user
profile.save()

另一种常见的解决方案是,在初始化表单时向用户提供,但是您必须稍微更改当前视图代码退出。

,

我实现了! 无需使用信号。以下是变化:

forms.py

我需要使用一个类:

class SignupForm(forms.ModelForm):

    first_name = forms.CharField(max_length=30,label="Nome")
    last_name = forms.CharField(max_length=30,label="Sobrenome")


    class Meta:
        model = UserProfile

        fields = ('sexo','data_nascimento','foto','sobre_mim','telefone','paroquia','cidade','estado','cep','possui_filhos','facebook','instagram')

        CIDADES = []
        for i in cidadesReader:
            if i[1] not in CIDADES:
                CIDADES.append(i[1])
        widgets = {
            'cidade': floppyforms.widgets.Input(datalist=CIDADES,attrs={'autocomplete': 'off'}),}

    field_order = ['first_name','last_name','email','password1','password2','sexo','instagram']


    def signup(self,request,user):
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        profile,created = models.UserProfile.objects.get_or_create(user=user)
        profile.sexo = self.cleaned_data['sexo']
        profile.data_nascimento = self.cleaned_data['data_nascimento']


        def compressImage(foto):
            ... 
            return foto


        profile.foto = compressImage (self.cleaned_data['foto'])
        profile.sobre_mim = self.cleaned_data['sobre_mim']
        profile.telefone = self.cleaned_data['telefone']
        profile.paroquia = self.cleaned_data['paroquia']
        profile.cidade = self.cleaned_data['cidade']
        profile.estado = self.cleaned_data['estado']
        profile.cep = self.cleaned_data['cep']
        profile.possui_filhos = self.cleaned_data['possui_filhos']
        profile.facebook = self.cleaned_data['facebook']
        profile.instagram = self.cleaned_data['instagram']
        user.save()
        profile.save()

注意:

我在 models.py 中使用了一个函数来压缩图像。 纠正错误

ValueError at /accounts/signup/
The 'foto' attribute has no file associated with it

我不得不把它带到forms.py

settings.py

ACCOUNT_SIGNUP_FORM_CLASS = 'profiles.forms.SignupForm'

models.py

class UserProfile(models.Model):
    user = models.OneToOneField(User,on_delete=models.CASCADE,unique=True,related_name ='profile')


    SEXOS = (
        ('M','Masculino'),('F','Feminino'),)
    sexo = models.CharField(max_length=1,choices=SEXOS)
    ...

注意:

有必要逐个字段进行测试。 有时会出现一些错误,例如 NOT NULL constraint failedno such table。 这些问题的解决方案:

  • 在字段中添加null=True(临时)
  • makemigrationsmigrate
  • 删除迁移

signup.html

只需要{{ form|crispy }}(我可以删除{{ profile_form|crispy }}

<form novalidate method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form|crispy }}
    <button class="btn btn-success" type="submit">Cadastrar</button>
</form>

感谢您的帮助,@Risadinha。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。