Cette question vise spécifiquement une réponse Django 2.0 car le module registration
n'est pas (encore) disponible pour cela.
De plus, cela peut sembler trop large, mais je me suis souvent retrouvé dans des situations où je ne peux pas utiliser de module tiers parce que ... eh bien .. politiques. J'en suis sûr que beaucoup l'ont fait. Et je sais que regarder et rassembler des informations tirées d'ici ou Django docs était un casse-tête.
Supposons que nous ayons besoin du flux suivant:
first_name
, last_name
et email
(l'e-mail sera utilisé comme nom d'utilisateur).Extra-info: L'utilisateur se connectera plus tard en utilisant son email (qui est en fait son nom d'utilisateur) et son mot de passe.
Tout d'abord, vous devrez créer un modèle User
personnalisé et un UserManager
personnalisé pour supprimer le champ username
et utiliser à la place email
.
Dans models.py
, Le UserManager
devrait ressembler à ceci:
from Django.contrib.auth.models import BaseUserManager
class MyUserManager(BaseUserManager):
"""
A custom user manager to deal with emails as unique identifiers for auth
instead of usernames. The default that's used is "UserManager"
"""
def _create_user(self, email, password, **extra_fields):
"""
Creates and saves a User with the given email and password.
"""
if not email:
raise ValueError('The Email must be set')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self._create_user(email, password, **extra_fields)
Et le modèle User
:
from Django.db import models
from Django.contrib.auth.models import AbstractBaseUser
from Django.contrib.auth.models import PermissionsMixin
from Django.utils.translation import ugettext_lazy as _
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, null=True)
is_staff = models.BooleanField(
_('staff status'),
default=False,
help_text=_('Designates whether the user can log into this 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.'
),
)
USERNAME_FIELD = 'email'
objects = MyUserManager()
def __str__(self):
return self.email
def get_full_name(self):
return self.email
def get_short_name(self):
return self.email
Et enfin dans settings.py
:
AUTH_USER_MODEL = ‘your_app_name.User’
La deuxième partie consiste à créer un générateur de jetons pour l'URL de confirmation de l'e-mail. Nous pouvons hériter du PasswordResetTokenGenerator
intégré pour le rendre plus facile.
Créez tokens.py
:
from Django.contrib.auth.tokens import PasswordResetTokenGenerator
from Django.utils import six
class TokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
return (
six.text_type(user.pk) + six.text_type(timestamp) +
six.text_type(user.is_active)
)
account_activation_token = TokenGenerator()
Ensuite, vous devez créer un formulaire d'inscription à utiliser dans nos vues. Le meilleur moyen est d'hériter du UserCreationForm
intégré de Django et d'en supprimer les champs username
et password
, puis d'ajouter un champ email
. forms.py
:
from Django import forms
from Django.contrib.auth.forms import UserCreationForm
from Django.contrib.auth.models import User
class SignupForm(UserCreationForm):
email = forms.EmailField(max_length=200, help_text='Required')
class Meta:
model = User
fields = ('email', 'first_name', 'last_name')
Lors de l'inscription, vous devez rendre l'utilisateur inactif user.is_active = False
Sans mot de passe set_unusable_password()
jusqu'à ce que l'utilisateur termine l'activation. Nous allons également créer une URL d'activation et l'envoyer par e-mail à l'utilisateur après avoir terminé l'enregistrement.
dans views.py
:
from Django.views import View
from Django.http import HttpResponse
from Django.shortcuts import render
from .forms import SignupForm
from Django.contrib.sites.shortcuts import get_current_site
from Django.utils.encoding import force_bytes
from Django.utils.http import urlsafe_base64_encode
from .tokens import account_activation_token
from Django.core.mail import EmailMessage
class Signup(View):
def get(self, request):
form = SignupForm()
return render(request, 'signup.html', {'form': form})
def post(self, request):
form = SignupForm(request.POST)
if form.is_valid():
# Create an inactive user with no password:
user = form.save(commit=False)
user.is_active = False
user.set_unusable_password()
user.save()
# Send an email to the user with the token:
mail_subject = 'Activate your account.'
current_site = get_current_site(request)
uid = urlsafe_base64_encode(force_bytes(user.pk))
token = account_activation_token.make_token(user)
activation_link = "{0}/?uid={1}&token{2}".format(current_site, uid, token)
message = "Hello {0},\n {1}".format(user.username, activation_link)
to_email = form.cleaned_data.get('email')
email = EmailMessage(mail_subject, message, to=[to_email])
email.send()
return HttpResponse('Please confirm your email address to complete the registration')
Et bien sûr, n'oubliez pas de créer un modèle pour votre vue d'inscription.
Ensuite, vous devez créer une vue pour que l'utilisateur active son compte en utilisant l'URL que nous avons créée dans la vue d'inscription. Nous utiliserons également le SetPasswordForm
de Django intégré pour permettre aux utilisateurs de définir leurs mots de passe.
Dans views.py
:
from Django.contrib.auth import get_user_model, login, update_session_auth_hash
from Django.contrib.auth.forms import PasswordChangeForm
from Django.utils.encoding import force_bytes, force_text
from Django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from .tokens import account_activation_token
User = get_user_model()
class Activate(View):
def get(self, request, uidb64, token):
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
except(TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and account_activation_token.check_token(user, token):
# activate user and login:
user.is_active = True
user.save()
login(request, user)
form = PasswordChangeForm(request.user)
return render(request, 'activation.html', {'form': form})
else:
return HttpResponse('Activation link is invalid!')
def post(self, request):
form = PasswordChangeForm(request.user, request.POST)
if form.is_valid():
user = form.save()
update_session_auth_hash(request, user) # Important, to update the session with the new password
return HttpResponse('Password changed successfully')
Encore une fois, n'oubliez pas de créer un modèle pour votre vue d'activation.
Enfin, dans urls.py
:
from . import views
from Django.urls import path
urlpatterns = [
...
path('signup/', views.signup.as_view(), name='signup'),
path('activate/<str:uid>/<str:token>', views.activate.as_view(), name='activate'),
]
P.S. Honnêtement, je n'ai pas encore eu l'occasion de tester toutes ces pièces ensemble, mais n'hésitez pas à demander si un problème s'est produit.
En plus de la réponse de Peter, si vous utilisez Django 2, les parties d'encodage et de décodage sont un peu différentes.
Encodage:
Modifier 'uid': urlsafe_base64_encode(force_bytes(user.pk)),
À 'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),
Décodage:
Modifier uid = force_text(urlsafe_base64_decode(uidb64))
À uid = urlsafe_base64_decode(uidb64).decode()
Vous pouvez appeler le formulaire de réinitialisation du mot de passe en passant l'e-mail des utilisateurs à partir de la demande. Cela envoie le lien en utilisant l'authentification intégrée. Vous souhaiterez peut-être remplacer le modèle par défaut pour le formulaire de courrier électronique et de mot de passe.
from Django.contrib.auth.forms import PasswordResetForm
# either the request or domain_override kwarg is needed
form = PasswordResetForm({'email': user.email})
if form.is_valid():
return form.save(
from_email='[email protected]',
# domain_override='your_domain',
request=request,
email_template_name='registration/password_reset_email.html'
)
Je suis sûr que vous avez besoin d'un mot de passe existant pour que cela fonctionne afin que vous puissiez en créer un factice temporaire
password = User.objects.make_random_password()
user.set_password(password)