代码之家  ›  专栏  ›  技术社区  ›  damon Curtis Snowden

在Django中接受电子邮件地址作为用户名

  •  80
  • damon Curtis Snowden  · 技术社区  · 16 年前

    在django有没有一个好的方法可以在不运行我自己的身份验证系统的情况下做到这一点?我希望用户名是用户的电子邮件地址,而不是他们创建的用户名。

    请指教,谢谢。

    12 回复  |  直到 16 年前
        1
  •  35
  •   Tom Christie    12 年前

    如果有人想这么做,我建议你看看 django-email-as-username 这是一个非常全面的解决方案,包括修补管理员和 createsuperuser 管理命令,以及其他零碎信息。

    编辑 :从Django 1.5开始,您应该考虑使用 custom user model 而不是 django电子邮件用户名 .

        2
  •  28
  •   Jonatan Littke Yukiup    13 年前

    这是我们要做的。这不是一个“完整”的解决方案,但它能满足你的大部分需求。

    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)
    
        3
  •  22
  •   owenfi    10 年前

    有一种方法可以同时接受用户名和电子邮件:

    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
    

    不知道是否有设置来设置默认身份验证表单,但也可以重写url.py中的url

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

    当提交无效电子邮件时,提升ValidationError将防止500个错误。使用super对“invalid_login”的定义会使错误消息保持不明确(与特定的“未找到该电子邮件的用户”相比),这将是防止泄露电子邮件地址是否已注册到您服务的帐户所必需的。如果该信息在您的体系结构中不安全,那么可能会有一个更具信息性的错误消息。

        4
  •  8
  •   Flimm D. Ben Knoble    8 年前

    Django现在提供了一个扩展身份验证系统的完整示例,其中包含管理和表单: https://docs.djangoproject.com/en/stable/topics/auth/customizing/#a-full-example

    你基本上可以复制/粘贴它并适应(我不需要 date_of_birth 就我而言)。

    它实际上是从Django 1.5开始提供的,现在仍然可以使用(django1.7)。

        5
  •  7
  •   Max Malysh    8 年前

    如果要扩展用户模型,无论如何都必须实现自定义用户模型。

    这里是Django 1.8的一个例子。Django 1.7需要更多的工作,主要是更改默认表单(只需看看 UserChangeForm &安培; UserCreationForm 在里面 django.contrib.auth.forms -这就是你在1.7中需要的。

    用户管理器.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
    

    型号.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)
    

    设置.py:

    AUTH_USER_MODEL = 'mainsite.SiteUser'
    
        6
  •  2
  •   Adrian Lopez    10 年前

    其他替代方案对我来说太复杂了,所以我编写了一个代码片段,允许使用用户名、电子邮件或两者进行身份验证,还允许启用或禁用区分大小写。我把它作为 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
    
        7
  •  1
  •   PhoebeB    13 年前

    最新版本的django注册允许一些很好的定制,可以在这里完成工作文档 https://bitbucket.org/ubernostrum/django-registration/src/fad7080fe769/docs/backend-api.rst

        8
  •  1
  •   syed    7 年前
         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()
    

    工作完美。。。对于django 1.11.4

        9
  •  0
  •   Rama Vadakattu    16 年前
        10
  •  0
  •   radtek    10 年前

    最简单的方法是根据登录视图中的电子邮件查找用户名。这样你就可以不去管其他事情了:

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

    在模板中相应地设置下一个变量,即。

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

    并输入正确的用户名/密码,即用户名、密码。

    更新 :

    或者,如果“是有效的”电子邮件(电子邮件):可以用用户名中的if“@”替换呼叫。这样您就可以删除有效的电子邮件功能。这真的取决于你如何定义你的用户名。如果您允许用户名中有“@”字符,它将不起作用。

        11
  •  0
  •   Enix    9 年前

    我认为最快的方法是创建一个继承自 UserCreateForm ,然后重写 username 字段 forms.EmailField . 然后,对于每个新的注册用户,他们需要用他们的电子邮件地址登录。

    例如:

    网址.py

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

    视图.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>
    ...
    
        12
  •  0
  •   Nick S.    9 年前

    不确定人们是否正在尝试完成这一点,但我找到了一个很好的(干净的)方法,只要求电子邮件,然后在保存之前将用户名设置为视图中的电子邮件。

    我的用户表单只需要电子邮件和密码:

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

    然后在我看来,我添加了以下逻辑:

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