如何解决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_CLASS 和 ACCOUNT_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 user
在 UserProfile.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 failed
或 no such table
。
这些问题的解决方案:
- 在字段中添加
null=True
(临时) -
makemigrations
和migrate
- 删除迁移
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 举报,一经查实,本站将立刻删除。