wake-up-neo.net

E-Mail-Adresse als Benutzername in Django akzeptieren

Gibt es eine gute Möglichkeit, dies in Django zu tun, ohne mein eigenes Authentifizierungssystem zu rollen? Ich möchte, dass der Benutzername die E-Mail-Adresse des Benutzers ist, anstatt einen Benutzernamen zu erstellen.

Bitte beraten, danke.

80
damon

Für alle anderen, die dies tun möchten, würde ich empfehlen, einen Blick auf Django-email-as-username zu werfen. Dies ist eine ziemlich umfassende Lösung, die das Patchen der Verwaltungsbefehle admin und createsuperuser neben anderen Bits und enthält Stücke.

Edit: Ab Django 1.5 sollten Sie die Verwendung eines benutzerdefinierten Benutzermodells anstelle von Django-email-as-username in Betracht ziehen.

34
Tom Christie

Hier ist was wir machen. Es ist keine "Komplettlösung", aber es macht vieles, wonach Sie suchen.

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)
27
S.Lott

Hier ist eine Möglichkeit, so dass sowohl Benutzername als auch E-Mail akzeptiert werden:

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

Ich weiß nicht, ob es eine Einstellung gibt, um das Standard-Authentifizierungsformular festzulegen, Sie können aber auch die URL in urls.py überschreiben

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

Durch das Auslösen des ValidationError werden 500 Fehler verhindert, wenn eine ungültige E-Mail gesendet wird. Wenn Sie die Definition des Supers für "invalid_login" verwenden, bleibt die Fehlermeldung mehrdeutig (im Gegensatz zu einem bestimmten "Kein Benutzer von dieser E-Mail gefunden"), der erforderlich ist, um zu verhindern, dass eine E-Mail-Adresse für ein Konto bei Ihrem Dienst angemeldet wird. Wenn diese Informationen in Ihrer Architektur nicht sicher sind, ist möglicherweise eine informativere Fehlermeldung angezeigt.

21
Juho Rutila

Django bietet jetzt ein vollständiges Beispiel für ein erweitertes Authentifizierungssystem mit Admin und Formular: https://docs.djangoproject.com/de/stable/topics/auth/customizing/#a-full-example

Sie können es grundsätzlich kopieren/einfügen und anpassen (in meinem Fall habe ich date_of_birth nicht benötigt).

Es ist eigentlich seit Django 1.5 verfügbar und ab sofort noch verfügbar (Django 1.7).

8
vinyll

Wenn Sie das Benutzermodell erweitern, müssen Sie das benutzerdefinierte Benutzermodell trotzdem implementieren. 

Hier ist ein Beispiel für Django 1.8. Django 1.7 würde ein wenig mehr Arbeit erfordern und meistens die Standardformulare ändern (siehe UserChangeForm & UserCreationForm in Django.contrib.auth.forms - das ist was Sie in 1.7 brauchen).

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)

einstellungen.py:

AUTH_USER_MODEL = 'mainsite.SiteUser'
7
Max Malysh

Andere Alternativen sehen für mich zu komplex aus. Deshalb habe ich ein Snippet geschrieben, mit dem Sie sich mit Benutzername, E-Mail oder beiden authentifizieren und die Groß- und Kleinschreibung aktivieren oder deaktivieren können. Ich habe es zu pip als Django-dual-authentication hochgeladen.

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
2
Adrian Lopez

Die neueste Version von Django-registration erlaubt einige nette Anpassungen und könnte die Arbeit erledigen - Dokumente hier https://bitbucket.org/ubernostrum/Django-registration/src/fad7080fe769/docs/backend-api.rst

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

perfekt funktionieren ... für Django 1.11.4

1
syed

Ich bin mir nicht sicher, ob die Leute versuchen, dies zu erreichen, aber ich fand es nett (und sauber), nur nach der E-Mail zu fragen und den Benutzernamen vor dem Speichern als E-Mail in der Ansicht festzulegen.

Meine UserForm erfordert nur die E-Mail und das Passwort:

class UserForm(forms.ModelForm):
    password = forms.CharField(widget=forms.PasswordInput())

    class Meta:
        model = User
        fields = ('email', 'password')

Dann füge ich meiner Ansicht nach die folgende Logik hinzu:

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()
0
Nick S.

Ich denke, der schnellste Weg ist, ein Formular zu erben, das von UserCreateForm erbt, und dann das Feld username mit forms.EmailField überschreiben. Für jeden neuen Registrierungsbenutzer muss er sich dann mit seiner E-Mail-Adresse anmelden.

Zum Beispiel:

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>
...
0
Enix

eine interessante Diskussion zu diesem Thema finden Sie auch unter dem folgenden Link:

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

0
Rama Vadakattu

Am einfachsten ist es, den Benutzernamen anhand der E-Mail in der Login-Ansicht nachzuschlagen. Auf diese Weise können Sie alles andere in Ruhe lassen:

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

Legen Sie in Ihrer Vorlage die nächste Variable entsprechend fest, d. H. 

<form method="post" class="form-login" action="{% url 'login' %}?next={{ request.GET.next }}" accept-charset="UTF-8">

Und geben Sie Ihren Benutzernamen/Passwort-Eingaben die richtigen Namen, d. H. Benutzername und Passwort.

UPDATE

Alternativ kann der Aufruf if _is_valid_email (email): durch if '@' im Benutzernamen ersetzt werden. Auf diese Weise können Sie die Funktion _is_valid_email löschen. Dies hängt wirklich davon ab, wie Sie Ihren Benutzernamen definieren. Es funktioniert nicht, wenn Sie in Ihren Benutzernamen das Zeichen '@' zulassen.

0
radtek