¿Hay alguna buena manera de hacer esto en django sin tener 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 que ellos creen un nombre de usuario.
Por favor avise, gracias.
python
django
authentication
demonio
fuente
fuente
Respuestas:
Para cualquier otra persona que desee hacer esto, recomiendo echar un vistazo a django-email-as-username, que es una solución bastante completa, que incluye parchear los
createsuperuser
comandos de administración y administración, entre otras partes.Editar : A partir de Django 1.5 en adelante, debería considerar usar un modelo de usuario personalizado en lugar de django-email-as-username .
fuente
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)
fuente
Aquí hay una forma de hacerlo para que se acepten tanto el nombre de usuario como el correo electrónico:
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'),
Al aumentar el ValidationError, se evitarán 500 errores cuando se envíe un correo electrónico no válido. El uso de la definición del 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 sería necesario para evitar filtrar 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 arquitectura, podría ser más amigable tener un mensaje de error más informativo.
fuente
Django ahora proporciona un ejemplo completo de un sistema de autenticación extendido con administrador y formulario: https://docs.djangoproject.com/en/stable/topics/auth/customizing/#a-full-example
Básicamente, puedes copiarlo / pegarlo y adaptarlo (no lo necesitaba
date_of_birth
en mi caso).En realidad, está disponible desde Django 1.5 y todavía está disponible a partir de ahora (django 1.7).
fuente
Si va a ampliar el modelo de usuario, tendrá que implementar un 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, principalmente cambiando los formularios predeterminados (solo eche un vistazo a
UserChangeForm
&UserCreationForm
indjango.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
formularios.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'
fuente
username
SiteUser
python manage.py makemigrations ...
ERRORS: <class 'accounts.admin.UserAdmin'>: (admin.E033) The value of 'ordering[0]' refers to 'username', which is not an attribute of 'accounts.User'.
username
campo a miUser
modelo con sunull=True
atributo. En esta entrada de la papelera de pegado, quería mostrar la implementación. pastebin.com/W1PgLrD9Otras alternativas me parecen demasiado complejas, así que escribí un fragmento que me permite autenticarme usando un nombre de usuario, correo electrónico o ambos, y también habilitar o deshabilitar la distinción entre 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
fuente
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
fuente
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
fuente
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
fuente
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 en paz:
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))
En su plantilla, establezca la siguiente variable en consecuencia, es decir
<form method="post" class="form-login" action="{% url 'login' %}?next={{ request.GET.next }}" accept-charset="UTF-8">
Y proporcione a sus entradas de nombre de usuario / contraseña los nombres correctos, es decir, nombre de usuario, contraseña.
ACTUALIZAR :
Alternativamente, la llamada if _is_valid_email (email): se puede reemplazar con if '@' en el nombre de usuario. De esa forma, puede eliminar la función _is_valid_email. Esto realmente depende de cómo defina su nombre de usuario. No funcionará si permite el carácter '@' en sus nombres de usuario.
fuente
Creo que la forma más rápida es crear un formulario heredado
UserCreateForm
y luego anular elusername
campo conforms.EmailField
. Luego, para cada nuevo usuario registrado, debe iniciar sesión con su dirección de correo electrónico.Por ejemplo:
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> ...
fuente
UserCreationForm
clase? Y por favor no recomiende escribir<input …
cuando, seguramente,{{form.username}}
es mejor.No estoy seguro de si las personas están tratando de lograr esto, pero encontré una manera agradable (y limpia) de solo pedir 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')
Luego, 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()
fuente