Y a-t-il un bon moyen de faire cela dans Django sans lancer mon propre système d'authentification? Je veux que le nom d'utilisateur soit l'adresse électronique de l'utilisateur au lieu de créer un nom d'utilisateur.
S'il vous plaît conseiller, merci.
Pour ceux qui voudraient faire cela, je vous conseillerais de regarder Django-email-as-username qui est une solution assez complète, qui inclut le correctif des commandes d'administration et de gestion createsuperuser
pièces.
Edit: à partir de Django 1.5, vous devriez envisager d’utiliser un modèle d’utilisateur personnalisé au lieu de Django-email-as-username .
Voici ce que nous faisons. Ce n'est pas une solution "complète", mais elle fait beaucoup de ce que vous recherchez.
from Django import forms
from Django.contrib import admin
from Django.contrib.auth.admin import UserAdmin
from Django.contrib.auth.models import User
class UserForm(forms.ModelForm):
class Meta:
model = User
exclude = ('email',)
username = forms.EmailField(max_length=64,
help_text="The person's email address.")
def clean_email(self):
email = self.cleaned_data['username']
return email
class UserAdmin(UserAdmin):
form = UserForm
list_display = ('email', 'first_name', 'last_name', 'is_staff')
list_filter = ('is_staff',)
search_fields = ('email',)
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
Voici une façon de le faire pour que le nom d'utilisateur et l'adresse électronique soient acceptés:
from Django.contrib.auth.forms import AuthenticationForm
from Django.contrib.auth.models import User
from Django.core.exceptions import ObjectDoesNotExist
from Django.forms import ValidationError
class EmailAuthenticationForm(AuthenticationForm):
def clean_username(self):
username = self.data['username']
if '@' in username:
try:
username = User.objects.get(email=username).username
except ObjectDoesNotExist:
raise ValidationError(
self.error_messages['invalid_login'],
code='invalid_login',
params={'username':self.username_field.verbose_name},
)
return username
Je ne sais pas s'il existe un paramètre pour définir le formulaire d'authentification par défaut, mais vous pouvez également remplacer l'URL dans urls.py
url(r'^accounts/login/$', 'Django.contrib.auth.views.login', { 'authentication_form': EmailAuthenticationForm }, name='login'),
La levée de ValidationError évitera 500 erreurs lorsqu'un courriel invalide est soumis. L'utilisation de la définition de super pour "invalid_login" conserve le message d'erreur ambigu (par opposition à un message spécifique "aucun utilisateur trouvé dans cet e-mail") qui serait nécessaire pour éviter la fuite si une adresse e-mail est enregistrée pour un compte sur votre service. Si cette information n’est pas sécurisée dans votre architecture, il pourrait être plus convivial d’avoir un message d’erreur plus informatif.
Django fournit maintenant un exemple complet de système d'authentification étendu avec admin et formulaire: https://docs.djangoproject.com/fr/stable/topics/auth/customizing/#a-full-example
Vous pouvez fondamentalement copier/coller et adapter (je n’avais pas besoin du date_of_birth
dans mon cas).
Il est actuellement disponible depuis Django 1.5 et est toujours disponible à partir de maintenant (Django 1.7).
Si vous souhaitez étendre le modèle utilisateur, vous devrez quand même implémenter un modèle utilisateur personnalisé.
Voici un exemple pour Django 1.8. Django 1.7 nécessiterait un peu plus de travail, changeant principalement les formulaires par défaut (jetez un coup d'œil à UserChangeForm
& UserCreationForm
dans Django.contrib.auth.forms
- c'est ce dont vous avez besoin dans 1.7).
user_manager.py:
from Django.contrib.auth.models import BaseUserManager
from Django.utils import timezone
class SiteUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
today = timezone.now()
if not email:
raise ValueError('The given email address must be set')
email = SiteUserManager.normalize_email(email)
user = self.model(email=email,
is_staff=False, is_active=True, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password, **extra_fields):
u = self.create_user(email, password, **extra_fields)
u.is_staff = True
u.is_active = True
u.is_superuser = True
u.save(using=self._db)
return u
models.py:
from mainsite.user_manager import SiteUserManager
from Django.contrib.auth.models import AbstractBaseUser
from Django.contrib.auth.models import PermissionsMixin
class SiteUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, blank=False)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
objects = SiteUserManager()
def get_full_name(self):
return self.email
def get_short_name(self):
return self.email
forms.py:
from Django.contrib import admin
from Django.contrib.auth.admin import UserAdmin
from Django.contrib.auth.forms import UserChangeForm, UserCreationForm
from mainsite.models import SiteUser
class MyUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = SiteUser
fields = ("email",)
class MyUserChangeForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = SiteUser
class MyUserAdmin(UserAdmin):
form = MyUserChangeForm
add_form = MyUserCreationForm
fieldsets = (
(None, {'fields': ('email', 'password',)}),
('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser',)}),
('Groups', {'fields': ('groups', 'user_permissions',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2')}
),
)
list_display = ('email', )
list_filter = ('is_active', )
search_fields = ('email',)
ordering = ('email',)
admin.site.register(SiteUser, MyUserAdmin)
settings.py:
AUTH_USER_MODEL = 'mainsite.SiteUser'
D'autres alternatives me paraissant trop complexes, j'ai donc écrit un extrait de code qui permet de s'authentifier à l'aide d'un nom d'utilisateur, d'un courrier électronique ou des deux, et d'activer ou de désactiver le respect de la casse. Je l'ai chargé sur pip sous le nom Django-dual-authentication .
from Django.contrib.auth.backends import ModelBackend
from Django.contrib.auth import get_user_model
from Django.conf import settings
###################################
""" DEFAULT SETTINGS + ALIAS """
###################################
try:
am = settings.AUTHENTICATION_METHOD
except:
am = 'both'
try:
cs = settings.AUTHENTICATION_CASE_SENSITIVE
except:
cs = 'both'
#####################
""" EXCEPTIONS """
#####################
VALID_AM = ['username', 'email', 'both']
VALID_CS = ['username', 'email', 'both', 'none']
if (am not in VALID_AM):
raise Exception("Invalid value for AUTHENTICATION_METHOD in project "
"settings. Use 'username','email', or 'both'.")
if (cs not in VALID_CS):
raise Exception("Invalid value for AUTHENTICATION_CASE_SENSITIVE in project "
"settings. Use 'username','email', 'both' or 'none'.")
############################
""" OVERRIDDEN METHODS """
############################
class DualAuthentication(ModelBackend):
"""
This is a ModelBacked that allows authentication
with either a username or an email address.
"""
def authenticate(self, username=None, password=None):
UserModel = get_user_model()
try:
if ((am == 'email') or (am == 'both')):
if ((cs == 'email') or cs == 'both'):
kwargs = {'email': username}
else:
kwargs = {'email__iexact': username}
user = UserModel.objects.get(**kwargs)
else:
raise
except:
if ((am == 'username') or (am == 'both')):
if ((cs == 'username') or cs == 'both'):
kwargs = {'username': username}
else:
kwargs = {'username__iexact': username}
user = UserModel.objects.get(**kwargs)
finally:
try:
if user.check_password(password):
return user
except:
# Run the default password hasher once to reduce the timing
# difference between an existing and a non-existing user.
UserModel().set_password(password)
return None
def get_user(self, username):
UserModel = get_user_model()
try:
return UserModel.objects.get(pk=username)
except UserModel.DoesNotExist:
return None
La dernière version de Django-registration permet une personnalisation de Nice et peut faire le travail - docs ici https://bitbucket.org/ubernostrum/Django-registration/src/fad7080fe769/docs/backend-api.rst
if user_form.is_valid():
# Save the user's form data to a user object without committing.
user = user_form.save(commit=False)
user.set_password(user.password)
#Set username of user as the email
user.username = user.email
#commit
user.save()
fonctionne parfaitement ... pour Django 1.11.4
Je ne suis pas sûr que les gens essaient d'accomplir cela, mais j'ai trouvé un moyen agréable (et propre) de demander uniquement le courrier électronique, puis de définir le nom d'utilisateur comme courrier électronique dans la vue avant de sauvegarder.
Mon UserForm nécessite uniquement l'adresse email et le mot de passe:
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('email', 'password')
Ensuite, à mon avis, j'ajoute la logique suivante:
if user_form.is_valid():
# Save the user's form data to a user object without committing.
user = user_form.save(commit=False)
user.set_password(user.password)
#Set username of user as the email
user.username = user.email
#commit
user.save()
Je pense que le moyen le plus rapide est de créer un formulaire hérité de UserCreateForm
, puis de remplacer le champ username
par forms.EmailField
. Ensuite, chaque nouvel utilisateur inscrit doit se connecter avec son adresse électronique.
Par exemple:
urls.py
...
urlpatterns += url(r'^signon/$', SignonView.as_view(), name="signon")
views.py
from Django.contrib.auth.models import User
from Django.contrib.auth.forms import UserCreationForm
from Django import forms
class UserSignonForm(UserCreationForm):
username = forms.EmailField()
class SignonView(CreateView):
template_name = "registration/signon.html"
model = User
form_class = UserSignonForm
signon.html
...
<form action="#" method="post">
...
<input type="email" name="username" />
...
</form>
...
vous pouvez également trouver une discussion intéressante sur ce sujet en cliquant sur le lien ci-dessous:
Le moyen le plus simple consiste à rechercher le nom d'utilisateur en fonction du courrier électronique dans la vue de connexion. De cette façon, vous pouvez laisser tout le reste seul:
from Django.contrib.auth import authenticate, login as auth_login
def _is_valid_email(email):
from Django.core.validators import validate_email
from Django.core.exceptions import ValidationError
try:
validate_email(email)
return True
except ValidationError:
return False
def login(request):
next = request.GET.get('next', '/')
if request.method == 'POST':
username = request.POST['username'].lower() # case insensitivity
password = request.POST['password']
if _is_valid_email(username):
try:
username = User.objects.filter(email=username).values_list('username', flat=True)
except User.DoesNotExist:
username = None
kwargs = {'username': username, 'password': password}
user = authenticate(**kwargs)
if user is not None:
if user.is_active:
auth_login(request, user)
return redirect(next or '/')
else:
messages.info(request, "<stvrong>Error</strong> User account has not been activated..")
else:
messages.info(request, "<strong>Error</strong> Username or password was incorrect.")
return render_to_response('accounts/login.html', {}, context_instance=RequestContext(request))
Dans votre modèle, définissez la variable suivante en conséquence, c'est-à-dire
<form method="post" class="form-login" action="{% url 'login' %}?next={{ request.GET.next }}" accept-charset="UTF-8">
Et donnez à votre nom d'utilisateur/mot de passe les bons noms, nom d'utilisateur, mot de passe.
METTRE &AGRAVE; JOUR:
Alternativement, l'appel if _is_valid_email (email): peut être remplacé par if '@' dans le nom d'utilisateur. De cette façon, vous pouvez supprimer la fonction _is_valid_email. Cela dépend vraiment de la façon dont vous définissez votre nom d'utilisateur. Cela ne fonctionnera pas si vous autorisez le caractère "@" dans vos noms d'utilisateur.