Как определить, был ли адрес электронной почты пользователя подтвержден с использованием Django, allauth, rest-auth и пользовательского пользователя
Я использую Django 2.0.10 с rest-framework, rest-auth и allauth. У меня есть пользовательская модель.
У меня есть проверка электронной почты с использованием представления Аллаута. Письмо с подтверждением отправляется, когда пользователь регистрируется. Если я нажму на ссылку в электронном письме, я попаду на страницу с кнопкой, чтобы проверить электронную почту. Это все работает без ошибок. Однако, что я не могу выяснить, что это на самом деле делает. Нет поля в данных пользователя, кажется, изменить.
Я хочу, чтобы пользователи могли регистрироваться и входить в систему, но добавлять контент на сайт только после того, как они подтвердили свою электронную почту.
Редактировать: этот пост дает часть ответа, но не говорит, как сохранить статус проверки как свойство пользователя, чтобы вы могли проверить его во внешнем интерфейсе при загрузке пользовательских данных.
settings.py
# django rest auth
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
OLD_PASSWORD_FIELD_ENABLED = True
LOGOUT_ON_PASSWORD_CHANGE = False
ACCOUNT_EMAIL_VERIFICATION = 'optional'
апи / urls.py
from allauth.account.views import confirm_email
urlpatterns = [
re_path(r'^rest-auth/registration/account-confirm-email/(?P<key>[-:\w]+)/$', confirm_email,
name='account_confirm_email'),
...
]
пользователи / models.py
import uuid
from django.contrib.auth.models import AbstractUser, UserManager
from django.db import models
from django.utils.http import int_to_base36
class CustomUserManager(UserManager):
def get_by_natural_key(self, username):
case_insensitive_username_field = '{}__iexact'.format(self.model.USERNAME_FIELD)
return self.get(**{case_insensitive_username_field: username})
ID_LENGTH = 12
def pkgen():
from base64 import b32encode
from hashlib import sha1
from random import random
pk = int_to_base36(uuid.uuid4().int)[:ID_LENGTH]
return pk
class CustomUser(AbstractUser):
objects = CustomUserManager()
slug = models.CharField(max_length=ID_LENGTH, default=pkgen, editable=False)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
def __str__(self):
return self.email
Когда пользователь входит в систему, как я могу узнать, подтвердили ли они свой адрес электронной почты? Спасибо за любую помощь!
4 ответа
Ага! Благодаря этому посту и этому посту, я думаю, что у меня есть ответ.
Статус адреса электронной почты сохраняется в отдельной таблице EmailAdress, а не в составе модели User. Это можно получить в наборе моделей следующим образом:
api.py
from allauth.account.admin import EmailAddress
class ListViewSet(viewsets.ModelViewSet):
...
def get_queryset(self):
# can view public lists and lists the user created
if self.request.user.is_authenticated:
print('is there a verified email address?')
print(EmailAddress.objects.filter(user=self.request.user, verified=True).exists())
...
Это вернет True, если у пользователя есть подтвержденный адрес электронной почты.
Однако гораздо полезнее добавить статус проверки пользователю. Это можно сделать с помощью сигнала, как описано здесь.
views.py
from allauth.account.signals import email_confirmed
from django.dispatch import receiver
@receiver(email_confirmed)
def email_confirmed_(request, email_address, **kwargs):
user = email_address.user
user.email_verified = True
user.save()
Теперь в api.py вы можете проверить это так:
print(self.request.user.email_verified)
Это работает, если у вас есть один адрес электронной почты, который нельзя изменить или удалить. Если вы разрешите несколько адресов электронной почты, я думаю, вам нужно будет сделать больше проверок и соответственно обновить статус пользователя. Но у меня есть только один адрес электронной почты, который используется для входа в систему, поэтому я думаю, что все в порядке.
Я думаю, что было бы лучше сделать 'email_verified' частью профиля пользователя, но это рабочая демонстрация.
Для этого есть функция.
Синтаксис:
from allauth.account.utils import has_verified_email
has_verified_email(user, email=None) -> bool
Согласно исходному коду, это делает то же самое, что и принятый ответ, когдаemail
являетсяNone
. В противном случае он проверяет, есть ли у пользователя подтвержденный адрес электронной почты.
У меня была такая же проблема, я смог решить ее, используя приведенный ниже код:
#Project-level folder urls.py
from django.contrib import admin
from django.urls import path, include
from allauth.account.views import ConfirmEmailView, EmailVerificationSentView
#These ConfirmEmailView, EmailVerificationSentView are very important
#I used other allauth/ dj-rest-auth views and they didn't automatically verify the email.
urlpatterns = [
path('admin/', admin.site.urls),
path('dj-rest-auth/registration/account-confirm-email/<str:key>/',
ConfirmEmailView.as_view()), #This is at the top because apparently won't work if below. #Integral to problem solution
path('dj-rest-auth/', include('dj_rest_auth.urls')),
path('dj-rest-auth/registration/', include('dj_rest_auth.registration.urls')),
path('api-auth', include('rest_framework.urls')),
path('dj-rest-auth/registration/account-confirm-email/',
EmailVerificationSentView.as_view(),
name='account_email_verification_sent'),#Integral to problem solution
]
Приведенный выше код позволил мне создавать новых пользователей с адресом регистрации. После чего отправляется электронное письмо со ссылкой. Когда пользователи нажимают на ссылку, они перенаправляются на страницу входа, а их адрес электронной почты проверяется в базе данных.
Попробуйте SerializerMethodField
Официальный пример:
from django.contrib.auth.models import User
from django.utils.timezone import now
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
days_since_joined = serializers.SerializerMethodField()
class Meta:
model = User
fields = '__all__'
def get_days_since_joined(self, obj):
return (now() - obj.date_joined).days