繁体   English   中英

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

[英]Django-allauth - Custom Sign Up with OneToOneField

使用两个分组的 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'}),            
        }

视图.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)

注册.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 %}

模型.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 save custom user profile fields with signup form

例如,我在models.py中对其进行了更改,并且确实进行了migrate

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.save()中触发了错误UserProfile has no user 您第一次在视图中使用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:

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', 'data_nascimento', 'foto', 'sobre_mim','telefone','paroquia',
                'cidade','estado', 'cep', 'possui_filhos', 'facebook', '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中使用 function 来压缩图像。 纠正错误

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

我不得不把它带到 forms.py

设置.py

ACCOUNT_SIGNUP_FORM_CLASS = 'profiles.forms.SignupForm'

模型.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 failed ou no such table 这些问题的解决方案:

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

注册.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。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM