django用户模型中有多个USERNAME_FIELD

时间:2015-07-12 16:39:55

标签: django django-authentication django-users

我的自定义用户模型:

ip2long()

有没有办法指定多个echo ip2long('192.168.1.13'); // 3221225472 ?像class MyUser(AbstractBaseUser): username = models.CharField(unique=True,max_length=30) email = models.EmailField(unique=True,max_length=75) is_staff = models.IntegerField(default=False) is_active = models.IntegerField(default=False) date_joined = models.DateTimeField(default=None) # Use default usermanager objects = UserManager() USERNAME_FIELD = 'email' 这样的东西,以便用户可以通过电子邮件和用户名登录?

6 个答案:

答案 0 :(得分:8)

USERNAME_FIELD设置不支持列表。您可以创建custom authentication backend,尝试在“电子邮件”或“用户名”字段中查找用户。

from django.db.models import Q

from django.contrib.auth import get_user_model

MyUser = get_user_model()

class UsernameOrEmailBackend(object):
    def authenticate(self, username=None, password=None, **kwargs):
        try:
           # Try to fetch the user by searching the username or email field
            user = MyUser.objects.get(Q(username=username)|Q(email=username))
            if user.check_password(password):
                return user
        except MyUser.DoesNotExist:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a non-existing user (#20760).
            MyUser().set_password(password)

然后,在settings.py设置AUTHENTICATION_BACKENDS到您的身份验证后端:

 AUTHENTICATION_BACKENDS = ('path.to.UsernameOrEmailBackend,)\

请注意,此解决方案并不完美。例如,密码重置只适用于USERNAME_FIELD设置中指定的字段。

答案 1 :(得分:8)

我们可以通过实施自己的电子邮件身份验证后端来实现这一目标。

您可以执行以下操作:

步骤1在设置中替换自定义用户模型:

由于我们不会使用Django的默认User模型进行身份验证,因此我们需要在MyUser中定义自定义settings.py模型。在项目设置中将MyUser指定为AUTH_USER_MODEL

AUTH_USER_MODEL = 'myapp.MyUser'

步骤2编写自定义身份验证后端的逻辑:

要编写我们自己的身份验证后端,我们需要实现至少两种方法,即get_user(user_id)authenticate(**credentials)

from django.contrib.auth import get_user_model
from django.contrib.auth.models import check_password

class MyEmailBackend(object):
    """
    Custom Email Backend to perform authentication via email
    """
    def authenticate(self, username=None, password=None):
        my_user_model = get_user_model()
        try:
            user = my_user_model.objects.get(email=username)
            if user.check_password(password):
                return user # return user on valid credentials
        except my_user_model.DoesNotExist:
            return None # return None if custom user model does not exist 
        except:
            return None # return None in case of other exceptions

    def get_user(self, user_id):
        my_user_model = get_user_model()
        try:
            return my_user_model.objects.get(pk=user_id)
        except my_user_model.DoesNotExist:
            return None

步骤3在设置中指定自定义身份验证后端:

编写自定义身份验证后端后,请在AUTHENTICATION_BACKENDS设置中指定此身份验证后端。

AUTHENTICATION_BACKENDS包含要使用的身份验证后端列表。 Django尝试在其所有身份验证后端进行身份验证。如果第一个身份验证方法失败,Django会尝试第二个身份验证方法,依此类推,直到尝试了所有后端。

AUTHENTICATION_BACKENDS = (
    'my_app.backends.MyEmailBackend', # our custom authentication backend
    'django.contrib.auth.backends.ModelBackend' # fallback to default authentication backend if first fails 
    )

如果通过MyEmailBackend进行身份验证失败,即用户无法通过email进行身份验证,那么我们将使用Django的默认身份验证ModelBackend,它将尝试通过{{1}进行身份验证} username模型的字段。

答案 2 :(得分:2)

不,您不能在USERNAME_FIELD中定义多个字段。

一种选择是编写自己的自定义登录以自行检查这两个字段。 https://docs.djangoproject.com/en/1.8/topics/auth/customizing/

即。将后端更改为您自己的。 AUTHENTICATION_BACKENDS然后编写一个authenticate方法并检查数据库中两个字段的用户名。

PS你可能想在你的模型上使用unique_together,这样你就不会遇到问题。

另一种选择是使用实际字段username来存储字符串和电子邮件。

答案 3 :(得分:0)

不幸的是,不是开箱即用。

auth contrib模块声明USERNAME_FIELD值是单值的。

请参阅https://github.com/django/django/search?q=USERNAME_FIELD

如果您想拥有一个多值USERNAME_FIELD,您将需要编写相应的逻辑或找到允许它的包。

答案 4 :(得分:0)

如果您的USERNAME_FIELD为DynamicFormCreation runTimeUiLibs; view = runTimeUiLibs.getRuntimeView(field, lastCoreFieldId, textviewid, edit, "0"); if (view != null) { LinearLayout fieldAndPrivacyLayout = UtilityClass .getLinearLayoutHorizontal(MainActivity.this); view.setLayoutParams(layoutParamsBasic); view.setId(Integer.parseInt(field.editProfileFieldId)); fieldAndPrivacyLayout.addView(view); editPageLayout.addView(fieldAndPrivacyLayout); } 并且用户使用username登录,那么您可以编写一个代码,使用提供的email获取username,然后使用该代码email以及username进行身份验证。

答案 5 :(得分:0)

REQUIRED_FIELDS = []
您可以定义多个 username_fields