python utilisée Accepter l'adresse e-mail comme nom d'utilisateur dans Django




il existe déjà un utilisateur avec l adresse e mail indiquée (10)

D'autres alternatives semblent trop complexes pour moi, j'ai donc écrit un extrait qui permet de s'authentifier en utilisant un nom d'utilisateur, un e-mail, ou les deux, et également activer ou désactiver la casse. Je l'ai téléchargé sur pip en tant que 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

Existe-t-il un bon moyen de le faire dans django sans avoir à lancer mon propre système d'authentification? Je souhaite que le nom d'utilisateur soit l'adresse e-mail de l'utilisateur au lieu de créer un nom d'utilisateur.

S'il vous plaît conseiller, merci.


Le moyen le plus simple consiste à rechercher le nom d'utilisateur en fonction de l'e-mail 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, à savoir

<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 entrées les bons noms, c'est-à-dire nom d'utilisateur, mot de passe.

MISE À 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.



Voici une façon de le faire afin que le nom d'utilisateur et le courriel 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'),

Augmenter le ValidationError permettra d'éviter 500 erreurs quand un email invalide est soumis. L'utilisation de la définition de super pour "invalid_login" maintient le message d'erreur ambigu (par rapport à un "aucun utilisateur par cet e-mail" spécifique) qui serait nécessaire pour éviter toute fuite si une adresse e-mail est inscrite pour un compte sur votre service. Si cette information n'est pas sécurisée dans votre architecture, il peut être plus convivial d'avoir un message d'erreur plus informatif.


     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 pense que le moyen le plus rapide est de créer un formulaire hérité de UserCreateForm , puis remplacer le champ de username avec forms.EmailField . Ensuite, pour chaque nouvel utilisateur d'inscription, ils doivent se connecter avec leur adresse e-mail.

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

Je ne sais pas si les gens essaient d'accomplir cela, mais j'ai trouvé une façon agréable (et propre) de ne demander que l'e-mail, puis de définir le nom d'utilisateur comme e-mail dans la vue avant de sauvegarder.

Mon UserForm nécessite uniquement l'adresse e-mail 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()

Voici ce que nous faisons. Ce n'est pas une solution "complète", mais elle fait beaucoup de ce que vous cherchez.

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)




authentication