Aceptar la dirección de correo electrónico como nombre de usuario en Django

¿Hay una buena manera de hacer esto en django sin utilizar mi propio sistema de autenticación? Quiero que el nombre de usuario sea la dirección de correo electrónico del usuario en lugar de crear un nombre de usuario.

Por favor avise, gracias.

Related of "Aceptar la dirección de correo electrónico como nombre de usuario en Django"

Para cualquier otra persona que quiera hacer esto, recomiendo echar un vistazo a django-email-as-username, que es una solución bastante completa, que incluye parchear el administrador y los comandos de administración createsuperuser , entre otros.

Edición : A partir de Django 1.5 en adelante, debe considerar usar un modelo de usuario personalizado en lugar de django-email-as-username .

Esto es lo que hacemos. No es una solución “completa”, pero hace mucho de lo que está buscando.

 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) 

Aquí hay una forma de hacerlo para que tanto el nombre de usuario como el correo electrónico sean aceptados:

 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 

No sé si hay alguna configuración para establecer el formulario de autenticación predeterminado, pero también puede anular la url en urls.py

 url(r'^accounts/login/$', 'django.contrib.auth.views.login', { 'authentication_form': EmailAuthenticationForm }, name='login'), 

El aumento de ValidationError evitará 500 errores cuando se envíe un correo electrónico no válido. El uso de la definición de super para “invalid_login” mantiene el mensaje de error ambiguo (frente a un “no se encontró ningún usuario por ese correo electrónico específico”) que se requeriría para evitar fugas si una dirección de correo electrónico está registrada para una cuenta en su servicio. Si esa información no está segura en su architecture, podría ser más amigable tener un mensaje de error más informativo.

Django ahora proporciona un ejemplo completo de un sistema de autenticación extendida con admin y formulario: https://docs.djangoproject.com/en/stable/topics/auth/customizing/#a-full-example

Básicamente, puede copiarlo / pegarlo y adaptarlo (no necesitaba la date_of_birth de date_of_birth en mi caso).

Actualmente está disponible desde Django 1.5 y aún está disponible a partir de ahora (django 1.7).

Si va a extender el modelo de usuario, tendrá que implementar el modelo de usuario personalizado de todos modos.

Aquí hay un ejemplo para Django 1.8. Django 1.7 requeriría un poco más de trabajo, en su mayoría, cambiar los formularios predeterminados (solo eche un vistazo a UserChangeForm & UserCreationForm en django.contrib.auth.forms , eso es lo que necesita en 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 

modelos.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' 

Otras alternativas me parecen demasiado complejas, por lo que escribí un fragmento de código que permite autenticar con un nombre de usuario, correo electrónico o ambos, y también habilitar o deshabilitar las mayúsculas y minúsculas. Lo subí a pip como 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 última versión de django-registration permite una buena personalización y podría hacer el trabajo, docs aquí 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() 

funcionando perfectamente … para django 1.11.4

También puede encontrar una discusión interesante sobre este tema en el siguiente enlace:

http://groups.google.com/group/django-users/browse_thread/thread/c943ede66e6807c/2fbf2afeade397eb#2fbf2afeade397eb

La forma más sencilla es buscar el nombre de usuario en función del correo electrónico en la vista de inicio de sesión. De esa manera puedes dejar todo lo demás solo:

 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, "Error User account has not been activated..") else: messages.info(request, "Error Username or password was incorrect.") return render_to_response('accounts/login.html', {}, context_instance=RequestContext(request)) 

En su plantilla establezca la siguiente variable en consecuencia, es decir

  

Y dé a sus entradas de nombre de usuario / contraseña los nombres correctos, es decir, nombre de usuario, contraseña.

ACTUALIZACIÓN :

Alternativamente, la llamada if _is_valid_email (correo electrónico): se puede reemplazar con if ‘@’ en el nombre de usuario. De esa manera puede eliminar la función _is_valid_email. Esto realmente depende de cómo definas tu nombre de usuario. No funcionará si permites el carácter ‘@’ en tus nombres de usuario.

Creo que la forma más rápida es crear un formulario heredado de UserCreateForm , y luego anular el campo de username con forms.EmailField . Campo de forms.EmailField . Luego, para cada nuevo usuario de registro, deben iniciar sesión con su dirección de correo electrónico.

Por ejemplo:

urls.py

 ... urlpatterns += url(r'^signon/$', SignonView.as_view(), name="signon") 

vistas.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

 ... 
... ...
...

No estoy seguro de si la gente está tratando de lograr esto, pero encontré una forma agradable (y limpia) de solo solicitar el correo electrónico y luego establecer el nombre de usuario como el correo electrónico en la vista antes de guardar.

Mi formulario de usuario solo requiere el correo electrónico y la contraseña:

 class UserForm(forms.ModelForm): password = forms.CharField(widget=forms.PasswordInput()) class Meta: model = User fields = ('email', 'password') 

Entonces en mi opinión agrego la siguiente lógica:

 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()