creamidea / Mushroom

To display Node Capture Data and Control it
Other
0 stars 1 forks source link

How to create custom user in Django #33

Open creamidea opened 10 years ago

creamidea commented 10 years ago

花了一段时间研究Django的用户模型User,一直想写出自己的用户模型,因为想加入自己的一些字段,比如:手机号码。但是之前一直没有尝试成功,今天终于成功了,于是将其整理如下:

首先,我使用的是Django 1.5.4,而这个版本「改经」了User,于是乎就不用像之前那么麻烦了。之前(根据搜索到的资料),开发者是不能扩展User字段的,只能添加一个类似于profile的模型和User关联,进行想过的操作。

在Django 1.5.4 中,可以使用以下方式解决:

in model.py

from django.contrib.auth.models import (User, AbstractBaseUser, AbstractUser, BaseUserManager, Group)

class MushroomUserManager(BaseUserManager):
    """
    # Mushroom房管理系统用户管理
    # 创建用户
    """

    def create_user(self, username, email=None, password=None, phone=None, **extra_fields):
        """
        Create and saves a User with the given username, email and password
        """
        now = timezone.now()
        if not username:
            raise ValueError(u'必须设置用户名')
        email = BaseUserManager.normalize_email(email)
        user = self.model(username=username, email=email, phone=phone,
                          is_staff=False, is_active=True, is_superuser=False,
                          last_login=now, date_joined=now, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, username, email, password, phone, **extra_fields):
        u = self.create_user(username, email, password, **extra_fields)
        u.phone = phone
        u.is_staff = True
        u.is_active = True
        u.is_superuser = True
        u.save(using=self._db)
        return u

class MushroomUser(AbstractUser):
    phone = models.CharField(u"phone", max_length=11,
                             help_text=u'通知用户的紧急号码', blank=True, null=True)
                            #注意这里,我需要添加null=True,blank=True, null=True,使这行运行被置空,否则会出现:IntegrityError XXX.phone may not be NULL
    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['email', 'phone'] #需要将其加入
    objects = MushroomUserManager()

    class Meta:
        # verbose_name = _('user')
        # verbose_name_plural = _('users')
        # abstract = True
        db_table = 'auth_user'   #请参考下面的comment,后来发现的问题
        swappable = 'AUTH_USER_MODEL'

    def get_phone(self):
        return self.phone

    def set_phone(self, phone):
        self.phone = phone

其实就是模仿contrib.auth.models中的User写的。根据我目前的理解,如果你要新建一个自己的用户模型,需要先创建一个自己的用户管理模型,而这个自己的用户模型可以继承BaseUserManager,然后实现两个方法,一个是创建用户的方法create_user和创建超级用户的方法create_superuser。

接下来就是创建自己的用户模型,将objects的值指定为你设置的用户管理模型即可。在自己定义的模型中就可以定义自己的字段了。嗯,差不多就是这个样子了。

对了,还要注意,在Django1.5.4中,还需要在settings.py中设置一个属性值,

#这里的account是我的用户管理app
AUTH_USER_MODEL = 'account.MushroomUser'

这样子差不多就大功告成了。

Reference:

  1. 基于 Django1.5自定义user模型
  2. django(v1.5) 自定义用户基础
  3. IntegrityError _id may not be NULL
  4. django / django / contrib / auth / models.py
  5. Django's AUTH_PROFILE_MODULE ( User Profile ) misbehaving
  6. get user profile in django
creamidea commented 10 years ago

本来以为大功告成,但是突然发现一个问题: 当自己创建用户的时候居然发现出错了,出错内容:

CommandError: One or more models did not validate:
mushroom.mushroomuser: Model has been swapped out for 'account.MushroomUser' whi
ch has not been installed or is abstract.
auth.user: Model has been swapped out for 'account.MushroomUser' which has not b
een installed or is abstract.
admin.logentry: 'user' has a relation with model account.MushroomUser, which has
 either not been installed or is abstract.

页面一直说auth_user( "no such table: auth_user"),找不到,后来我听从网上的一个教程说的,改变了表的名称:

 db_table = 'auth_user'

也就是这个样子:

class MushroomUser(AbstractUser):
    ...
    class Meta:
        db_table = 'auth_user'
        swappable = 'AUTH_USER_MODEL'
    ...

Reference:

creamidea commented 10 years ago

If you really want to use a model reference to the User, you can wirte it like this:

class UserProfile(models.Model):
    # you add this line in you code
    user = models.OneToOneField(User)

    university = models.ForeignKey('University')
    course_title = models.ForeignKey('Course_Title')

    class Meta:
        db_table = 'user_profile'

def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)

post_save.connect(create_user_profile, sender=User)

Reference: UserCreationForm in Django with extra fields when a foreign key exists