我想用一些基本信息(姓名,公司...)和电子邮件注册用户。用户提交表单后,我想发送一封电子邮件,其中包含一个链接,该链接将用户带到设置其密码的页面。
我已经尝试了这个问题的解决方案: Django AllAuth - 如何手动发送重置密码电子邮件? 电子邮件已发送,电子邮件中的链接正常工作,但我在我的网站上收到断言错误。 错误出在setup_user_email(request, user, addresses)
函数内部的/allauth/account/utils.py
中。行:assert not EmailAddress.objects.filter(user=user).exists()
我在这里做错了什么?
我 models.py:
from django.contrib.auth.models import AbstractUser
from django.db import models
from allauth.account.views import PasswordResetView
from django.conf import settings
from django.dispatch import receiver
from django.http import HttpRequest
from django.middleware.csrf import get_token
class Kompanija(models.Model):
naziv = models.CharField(max_length=50)
adresa = models.CharField(max_length=50, blank=True)
def __str__(self):
return self.naziv
class Meta:
verbose_name = "Kompanija"
verbose_name_plural = "Kompanije"
class CustomUser(AbstractUser):
ime = models.CharField(max_length=30, default='')
prezime = models.CharField(max_length=30, default='')
kompanija = models.ForeignKey(Kompanija, on_delete=models.CASCADE, null=True, blank=True)
is_premium = models.BooleanField('premium status', default=False)
def __str__(self):
return self.ime + " " + self.prezime
@receiver(models.signals.post_save, sender=settings.AUTH_USER_MODEL)
def send_reset_password_email(sender, instance, created, **kwargs):
if created:
request = HttpRequest()
request.method = 'POST'
if settings.DEBUG:
request.META['HTTP_HOST'] = 'www.zahtjevi.com'
else:
request.META['HTTP_HOST'] = 'www.zahtjevi.com'
request.POST = {
'email': instance.email,
'csrfmiddlewaretoken': get_token(HttpRequest())
}
PasswordResetView.as_view()(request)
我 adapter.py:
from allauth.account.adapter import DefaultAccountAdapter
from .models import Kompanija
class UserAccountAdapter(DefaultAccountAdapter):
def save_user(self, request, user, form, commit=True):
user = super(UserAccountAdapter, self).save_user(request, user, form, commit=False)
user.ime = form.cleaned_data.get('ime')
user.prezime = form.cleaned_data.get('prezime')
user.kompanija = Kompanija.objects.get(id=form.cleaned_data.get('kompanija'))
user.is_active = True
user.save()
我 forms.py:
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from allauth.account.forms import SignupForm
from .models import CustomUser, Kompanija
class CustomUserCreationForm(UserCreationForm):
ime = forms.CharField(max_length=30, label='Ime')
prezime = forms.CharField(max_length=30, label='Prezime')
kompanija = forms.CharField(widget=forms.HiddenInput())
class Meta(UserCreationForm):
model = CustomUser
fields = ('username', 'email', 'ime', 'prezime')
class CustomUserChangeForm(UserChangeForm):
ime = forms.CharField(max_length=30, label='Ime')
prezime = forms.CharField(max_length=30, label='Prezime')
kompanija = forms.CharField(widget=forms.HiddenInput())
class Meta:
model = CustomUser
fields = ('username', 'email', 'ime', 'prezime')
class CustomSignupForm(SignupForm):
ime = forms.CharField(max_length=30, label='Ime')
prezime = forms.CharField(max_length=30, label='Prezime')
kompanija = forms.CharField(widget=forms.HiddenInput())
class Meta:
model = CustomUser
def signup(self, request, user):
user.ime = self.cleaned_data['ime']
user.prezime = self.cleaned_data['prezime']
user.kompanija = Kompanija.objects.get(id=self.cleaned_data['kompanija'])
user.is_active = True
user.save()
return user
class CustomUserAdminForm(forms.ModelForm):
class Meta:
model = CustomUser
fields = ('email', 'ime', 'prezime', 'username', 'kompanija', 'is_premium')
更新 1:
错误回溯:
Environment:
Request Method: POST
Request URL: https://www.zahtjevi.com/accounts/signup/
Django Version: 2.2.3
Python Version: 3.7.0
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'debug_toolbar',
'allauth',
'allauth.account',
'allauth.socialaccount',
'korisnici.apps.KorisniciConfig',
'pages.apps.PagesConfig',
'projekti.apps.ProjektiConfig',
'zahtjevi.apps.ZahtjeviConfig']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware']
Traceback:
File "/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/core/handlers/exception.py" in inner
34. response = get_response(request)
File "/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/core/handlers/base.py" in _get_response
115. response = self.process_exception_by_middleware(e, request)
File "/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/core/handlers/base.py" in _get_response
113. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/views/generic/base.py" in view
71. return self.dispatch(request, *args, **kwargs)
File "/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/utils/decorators.py" in _wrapper
45. return bound_method(*args, **kwargs)
File "/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/views/decorators/debug.py" in sensitive_post_parameters_wrapper
76. return view(request, *args, **kwargs)
File "/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/views.py" in dispatch
214. return super(SignupView, self).dispatch(request, *args, **kwargs)
File "/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/views.py" in dispatch
80. **kwargs)
File "/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/views.py" in dispatch
192. **kwargs)
File "/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/views/generic/base.py" in dispatch
97. return handler(request, *args, **kwargs)
File "/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/views.py" in post
103. response = self.form_valid(form)
File "/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/views.py" in form_valid
230. self.user = form.save(self.request)
File "/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/forms.py" in save
407. setup_user_email(request, user, [])
File "/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/utils.py" in setup_user_email
254. assert not EmailAddress.objects.filter(user=user).exists()
Exception Type: AssertionError at /accounts/signup/
Exception Value:
更新 2:
当用户提交注册表单时,将引发此错误。 在我的forms.py
中,我有一个向用户显示的CustomSignupForm
。 调用的观点来自 django-allauth(我在我的 urls.pypath('accounts/', include('allauth.urls')),
我试图从我的表单中删除save()
,但错误仍然存在,如果我删除settings.py
内的ACCOUNT_ADAPTER
变量,错误仍然存在......
更新 3:
从 django-debug-toolbar 我看到:
SELECT (1) AS `a`
FROM `account_emailaddress`
WHERE `account_emailaddress`.`email` LIKE 'dario@igl.hr'
LIMIT 1
2 similar queries. Duplicated 2 times.
/bin/user_wsgi_wrapper.py in __call__(202)
app_iterator = self.app(environ, start_response)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/contrib/staticfiles/handlers.py in __call__(65)
return self.application(environ, start_response)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/views/generic/base.py in view(71)
return self.dispatch(request, *args, **kwargs)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/views/decorators/debug.py in sensitive_post_parameters_wrapper(76)
return view(request, *args, **kwargs)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/views.py in dispatch(214)
return super(SignupView, self).dispatch(request, *args, **kwargs)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/views.py in dispatch(80)
**kwargs)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/views.py in dispatch(192)
**kwargs)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/views/generic/base.py in dispatch(97)
return handler(request, *args, **kwargs)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/views.py in post(103)
response = self.form_valid(form)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/views.py in form_valid(230)
self.user = form.save(self.request)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/forms.py in save(404)
adapter.save_user(request, user, self)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/adapter.py in save_user(243)
user.save()
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/contrib/auth/base_user.py in save(66)
super().save(*args, **kwargs)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/dispatch/dispatcher.py in send(175)
for receiver in self._live_receivers(sender)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/dispatch/dispatcher.py in <listcomp>(175)
for receiver in self._live_receivers(sender)
/home/filozof/nadzor/korisnici/models.py in send_reset_password_email(51)
PasswordResetView.as_view()(request)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/views/generic/base.py in view(71)
return self.dispatch(request, *args, **kwargs)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/views/generic/base.py in dispatch(97)
return handler(request, *args, **kwargs)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/views.py in post(103)
response = self.form_valid(form)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/views.py in form_valid(644)
form.save(self.request)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/forms.py in save(516)
temp_key = token_generator.make_token(user)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/contrib/auth/tokens.py in make_token(21)
return self._make_token_with_timestamp(user, self._num_days(self._today()))
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/django/contrib/auth/tokens.py in _make_token_with_timestamp(60)
self._make_hash_value(user, timestamp),
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/forms.py in _make_hash_value(41)
sync_user_email_addresses(user)
/home/filozof/.virtualenvs/django2/lib/python3.7/site-packages/allauth/account/utils.py in sync_user_email_addresses(350)
and EmailAddress.objects.filter(email__iexact=email).exists():
问题出在 allauthSignupForm
的save()
方法上:它首先保存用户,然后在最后设置用户的EmailAddress
(它有一个单独的用户电子邮件地址模型)。
def save(self, request):
...
adapter.save_user(request, user, self) # this calls your post-save signal
self.custom_signup(request, user) # this should call your custom signup method in your custom signup form
setup_user_email(request, user, []) # this raises the exception
return user
现在,密码重置视图/窗体可确保正确设置用户的EmailAddress
(因此它将user.email
添加为EmailAddress
模型)。由于这是由您的post_save
信号完成的,因此它会在调用setup_user_email
之前发生。
您应该:
- 删除
post_save
信号处理程序,因为它总是会在setup_user_email
之前调用。
将 代码以将重置密码电子邮件发送到表单的
save()
方法中(首先调用上述super().save()
方法,然后发送密码重置电子邮件。# in your custom form def save(self, request): user = super().save(request) new_request = HttpRequest() new_request.method = 'POST' new_request.META['HTTP_HOST'] = 'www.zahtjevi.com' new_request.POST = { 'email': user.email, 'csrfmiddlewaretoken': get_token(new_request) } PasswordResetView.as_view()(new_request) return user
注意:我感觉您的自定义表单根本没有被使用,您是否按照此处的规定在ACCOUNT_FORMS
中定义了它?
注意2(已编辑):表单的signup()
方法是超凡的,它与自定义适配器的save_user()
方法执行相同的操作。删除两者之一,可能是窗体的signup()
方法,这样您就不会点击 db 两次来保存user
对象。