Djangoの会員登録機能実装において、仮登録でメアドとパスワード保存→本登録他の情報を保存するとでIntegrityErrorが出てしまう
- 評価
- クリップ 0
- VIEW 469
前提・実現したいこと
DjangoでWebサイトの会員登録機能を作成しようとしています。
コードの参考に以下のサイトを参考にさせていただいています。
https://blog.narito.ninja/detail/38/
実現したいことは、
①会員登録ページからメールアドレス、パスワードを入力する。
②送信ボタンを押すとユーザー情報を保存し、仮登録完了メールを送信する。
③届いたメールに添付されたURLをクリックする。
④開かれたURLのなかで、追加の会員情報として名字、名前、会社名、住所を入力する。
⑤完了ボタンを押して、ユーザー情報を保存し、本登録完了ページへ移行する。
という流れの実装です。
しかし⑥で以下のエラーメッセージが発生しました。
メールアドレス、パスワードを登録した上で、追加で名字、名前、会社名、住所を登録したいと考えているのですが、下記エラーが出てしまいます。解決策を教えていただければ幸いです。
初心者マークをつけ忘れたので一度更新しました。
発生している問題・エラーメッセージ
IntegrityError at user_create/detail/Mze:1k3uvF:CJK6fjLLY4xYk0CaUt1K2qFZqJM/
UNIQUE constraint failed: app_user.email
該当のソースコード
class UserCreateForm(UserCreationForm):
"""ユーザー仮登録用フォーム"""
class Meta:
model = User
fields = ('email',)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self.fields.values():
field.widget.attrs['class'] = 'form-control'
def clean_email(self):
email = self.cleaned_data['email']
User.objects.filter(email=email, is_active=False).delete()
return email
class UserAddForm(forms.ModelForm):
"""ユーザー本登録用フォーム"""
class Meta:
model = User
fields = ('first_name','last_name','company','address',)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self.fields.values():
field.widget.attrs['class'] = 'form-control'
class UserCreateDetail(generic.CreateView):
"""メール内URLアクセス後のユーザー本登録"""
model = User
form_class = UserAddForm
template_name = 'app/user_create_detail.html'
timeout_seconds = getattr(settings, 'ACTIVATION_TIMEOUT_SECONDS', 60*60*24)
def get(self, request, **kwargs):
"""tokenが正しければ仮登録の情報保存."""
token = kwargs.get('token')
try:
user_pk = loads(token, max_age=self.timeout_seconds)
# 期限切れ
except SignatureExpired:
return HttpResponseBadRequest()
# tokenが間違っている
except BadSignature:
return HttpResponseBadRequest()
# tokenは問題なし
else:
try:
user = User.objects.get(pk=user_pk)
except User.DoesNotExist:
return HttpResponseBadRequest()
else:
if not user.is_active:
# 問題なければ仮登録の情報保存(本登録はマダ)
user.is_active = False
user.save()
return super().get(request, **kwargs)
return HttpResponseBadRequest()
def get_success_url(self):
return resolve_url('app:user_create_complete', pk=self.kwargs['pk'])
class UserCreateComplete(generic.TemplateView):
"""ユーザー本登録"""
template_name = 'app/user_create_complete.html'
timeout_seconds = getattr(settings, 'ACTIVATION_TIMEOUT_SECONDS', 60*60*24) # デフォルトでは1日以内
def get(self, request, **kwargs):
"""tokenが正しければ本登録."""
token = kwargs.get('token')
try:
user_pk = loads(token, max_age=self.timeout_seconds)
# 期限切れ
except SignatureExpired:
return HttpResponseBadRequest()
# tokenが間違っている
except BadSignature:
return HttpResponseBadRequest()
# tokenは問題なし
else:
try:
user = User.objects.get(pk=user_pk)
except User.DoesNotExist:
return HttpResponseBadRequest()
else:
if not user.is_active:
# 問題なければ本登録とする
user.is_active = True
user.save()
return super().get(request, **kwargs)
return HttpResponseBadRequest()
class User(AbstractBaseUser, PermissionsMixin):
"""カスタムユーザーモデル."""
email = models.EmailField(_('メールアドレス'), unique=True)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=150, blank=True)
company = models.CharField(_('会社名'), max_length=150, blank=True)
address = models.CharField(_('住所'), max_length=150, blank=True)
is_staff = models.BooleanField(
_('staff status'),
default=False,
help_text=_(
'Designates whether the user can log into this admin site.'),
)
is_active = models.BooleanField(
_('active'),
default=True,
help_text=_(
'Designates whether this user should be treated as active. '
'Unselect this instead of deleting accounts.'
),
)
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
objects = CustomUserManager()
last_login = models.DateTimeField(_('last_login'), default=timezone.now)
EMAIL_FIELD = 'email'
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def get_full_name(self):
"""Return the first_name plus the last_name, with a space in
between."""
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
"""Return the short name for the user."""
return self.first_name
def email_user(self, subject, message, from_email=None, **kwargs):
"""Send an email to this user."""
send_mail(subject, message, from_email, [self.email], **kwargs)
@property
def username(self):
"""username属性のゲッター
他アプリケーションが、username属性にアクセスした場合に備えて定義
メールアドレスを返す
"""
return self.email
from django.contrib import admin
from django.urls import path,include
from . import views
app_name = 'app'
urlpatterns = [
~ 省略~
path('user_create/detail/<token>/', views.UserCreateDetail.as_view(), name='user_create_detail'),
path('user_create/complete/<int:pk>/', views.UserCreateComplete.as_view(), name='user_create_complete'),
]
試したこと
class UserCreateDetail(generic.CreateView):にある def get_success_url(self):の中身に、
user = form.save(commit=False)
user.is_active = False
user.save()
など、ユーザー情報を保存するための方法を色々試しました。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
まだ回答がついていません
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.21%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
質問への追記・修正の依頼
tatamyiwathy
2020/08/07 17:47
同じemailがすでに登録されていませんか?
future0708
2020/08/07 19:00
質問ありがとうございます。
確認しsq.lite3も消してみたのですがうまくいきませんでした。
dameo
2020/08/08 01:33
色々試すのではなく、100%起きる現象ならデバッガでおっかけて、正確な原因を確かめてください。
また、デバッグ実行しているならスタックトレースも出ているはずなので、それを貼りましょう。
正確な原因が分かった上で対策が分からないのであれば、現象を再現できる最小のそれだけで動くコードを作成して、それをベースに質問してください。原因となる部分が掲載されているかどうか分からない、部分コードだけ見せられても、対応してくれる人は稀だと思います。
ForestSeo
2020/08/08 15:53
なぜか
if not user.is_active:
⠀⠀⠀# 問題なければ仮登録の情報保存(本登録はマダ)
⠀⠀⠀user.is_active = False
⠀⠀⠀user.save()
⠀⠀⠀return super().get(request, **kwargs)
で、if not user.is_activeでuser.is_active=Falseにして保存してるのが気になる。