Contents:

Django权限系统


1450 浏览 5 years, 11 months

2 用户扩展 (支持电话号码)

版权声明: 转载请注明出处 http://www.codingsoho.com/

用户扩展 (支持电话号码)

用户扩展包括以下几种方法

  • (1) 直接修改django 源码
  • (2) 把django 的user以及认证部分的源代码拷贝到自己的app下面
  • (3) OneToOneField扩展
  • (4) Profile Model (1.5之后不再支持)
  • (5) AbstractBaseUser, PermissionsMixin开始派生出一个自定用户Model,并且实现自定义的BaseUserManager (1.5之后)
  • (6) ProfileBase(type)
  • (7) 继承User

(1)(2),每次升级之后都要修改,维护成本太高
(3) 这个在原始的用户扩展中一般不用,因为会增加新的Models,但是对于额外的用户信息一般采用这种方法,比如微信用户,支付用户等等
(4) 不再支持
(5) 本文会采用该方法
(7) 从它的基类继承会更灵活

添加用户域

新的用户域如下

Field Type Property Description
username CharField unique 用户名 [如果电话注册= phone]
phone CharField 电话
first_name CharField
last_name CharField
email EmailField 邮箱
sex CharField 性别
birthday DateField 生日
nickname CharField 昵称
image ImageField 头像
is_staff BooleanField 职员状态 指明用户是否可以登录到这个管理站点。<br> Boolean. Designates whether this user can access the admin site.
is_super BooleanField 超级用户状态 指明该用户缺省拥有所有权限。<br> Boolean. Designates that this user has all permissions without explicitly assigning them.
is_active BooleanField 有效 <br> 指明用户是否被认为活跃的。以反选代替删除帐号。 <br>Boolean. Designates whether this user account should be considered active. Set this flag to False instead of deleting accounts.
date_joined DateTimeField 加入时间
account_type CharField [mail, phone] 注册类型

authwrapper\models.py

from __future__ import unicode_literals
from authwrapper.fields import EmailNullField, PhoneNumberNullField
from authwrapper.validators import (ASCIIUsernameValidator,
                                    UnicodeUsernameValidator)

class MyUser(MyAbstractUser):
    class Meta(MyAbstractUser.Meta):
        swappable = 'AUTH_USER_MODEL'

class MyAbstractUser(AbstractBaseUser, PermissionsMixin):
#
    username_validator = UnicodeUsernameValidator() if six.PY3 else ASCIIUsernameValidator()
    username = models.CharField(_('username'), 
        max_length=30, 
        unique=True,
        help_text=_('Required. 30 characters or fewer. Letters, digits and '
                    '@/./+/-/_ only.'),                    
        #validators=[
        #    validators.RegexValidator(r'^[\w.@+-]+$',
        #                              _('Enter a valid username. '
        #                                'This value may contain only letters, numbers '
        #                                'and @/./+/-/_ characters.'), 'invalid'),
        #],        
        validators=[username_validator],
        error_messages={
            'unique': _("A user with that username already exists."),
        })
    email = EmailNullField(_('email address'), max_length=255,null=True, blank=True, unique=True)
    phone = PhoneNumberNullField(_('phone'), max_length=30, blank=True, unique=True,
        help_text=_('Required. digits and + only.'),
        error_messages={
            'unique': _("A user with that phone number already exists."),
        })
#        
    account_type = models.CharField(max_length=50, blank=True, null=True, choices=USER_TYPE, default = 'username') #login account type
#
    USERNAME_FIELD = 'phone' if 'phone' == settings.ACCOUNT_REGISTER_TYPE  else 'username'
    REQUIRED_FIELDS = ['email'] if 'phone' == settings.ACCOUNT_REGISTER_TYPE  else ['phone','email']
#    
    objects = MyUserManager()
# 
    class Meta:
        verbose_name = _('user')
        verbose_name_plural = _('users')
        abstract = True
  1. 添加新的filed phone
  2. 首先安装库django-phonenumber-field
  3. PhoneNumberNullField从PhoneNumberField继承而来,当内容为空时保存为Null
  4. phone number的validation会在这个field内完成

  5. 扩展EmailField为EmailNullField

  6. 添加Username的validator,支持py3和py2 下面这句话是为了兼容py3

from __future__ import unicode_literals
  1. 在settings.py里添加配置ACCOUNT_REGISTER_TYPE,指示默认注册方式是邮件还是电话号码

  2. 根据ACCOUNT_REGISTER_TYPE确定USERNAME_FIELD和REQUIRED_FIELDS

  3. swappable = 'AUTH_USER_MODEL'

    swappable is an "intentionally undocumented" feature which is currently under development / in-test. It's used to handle "I have a base abstract model which has some foreign-key relationships." Slightly more detail is available from Django's ticketing system and github. Because it's a "stealth alpha" feature, it's not guaranteed to work (for anything other than User), and understanding the detailed operation will likely require diving into source code. It works with AUTH_USER_MODEL because the User model and swappable flag were developed together, specifically for each other.

修改AUTH_USER_MODEL

在settings.py添加

AUTH_USER_MODEL = 'authwrapper.MyUser'

以后调用新用户时,可以用django.contrib.auth.get_user_model或者settings.AUTH_USER_MODEL

信号

django系统里面username是默认存在,如果用电话号码注册,这个信息一开始并不是必须的,为了通过django的验证,暂时通过设置username=phone来保证models的validation

authwrapper\models.py

def myuser_pre_save_receiver(sender, instance, *args, **kwargs):
    if 'phone' == MyUser.USERNAME_FIELD:
        if instance.username is None: # hide username and copy value from phone number
            instance.username = instance.phone

pre_save.connect(myuser_pre_save_receiver, sender=MyUser)

添加用户及管理

authwrapper\models.py

    def _create_user(self, username, email, phone, password, **extra_fields):
        """
        Creates and saves a User with the given username, email and password.
        """
        now = timezone.now()
        if not username:
            raise ValueError('The given username must be set')
        email = self.normalize_email(email)
        user = self.model(username=username, 
                          email=email,
                          phone=phone,
                          date_joined=now, 
                          **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

class MyUserManager(BaseUserManager):
    def create_user(self, username, email=None, phone=None, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(username, email, phone, password, **extra_fields)

    def create_superuser(self, username, email, phone, password, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self._create_user(username, email, phone, password,
                                 **extra_fields)                 

执行python manage.py createsuperuser时会调用上面的函数,可以通过修改django\contrib\auth\management\commands\createsuperuser做进一步的修改