Django实践:自定义用户系统

论坛 期权论坛 脚本     
匿名技术用户   2020-12-29 02:37   595   0

本文基于Django1.5来讨论。http://lukecafe.com/2013/04/django-in-actioncustomize-user-system/

Django自带了一个用户系统以及很好用的认证,如果能够很方便地扩展的话,没有理由不用它的。扩展Django的用户系统有几个方法:

  1. 在自定义Model中使用OneToOneField的方式来扩展,实现一个User Profile。这种方式在1.5之前是推荐的,在User也有一个默认的get_profile方法来获取这个profile。这种方式的好处是1.5以前的版本默认支持,并且对Django的影响最小,坏处主要是获取资料的时候需要一次join表。这种方式的示例代码如下:

    class UserProfile(models.Model): user = models.OneToOneField('auth.User') bio = models.TextField()

  2. 从Django的User派生或者重写,这样要比较小心地满足Django一些耦合的地方,才能利用起Django的用户认证和管理。这种方式不推荐,维护起来很麻烦,也容易产生冲突。

  3. 在Django1.5开始加强了用户自定义的功能,从AbstractBaseUser, PermissionsMixin开始派生出一个自定用户Model,并且实现自定义的BaseUserManager就能够使用Django来创建用户。为了在Django管理界面管理自定义的用户,还需要实现自定义的UserAdmin。下面是例子:

我把用户系统建在base这个app里面,更常用的做法应该是放到单独的用户app譬如user或者account下面。在base/models.py放以下代码:

from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, PermissionsMixin

class MyUserManager(BaseUserManager):
    def create_user(self, nick_name, email, password, **extra_fields):
        if not email:
            raise ValueError('Users must have an email address')
 
        user = self.model(
            nick_name=nick_name,
            email=MyUserManager.normalize_email(email),
            is_staff=False, 
            is_active=True, 
            is_superuser=False,
            **extra_fields
        )
        user.set_password(password)
        user.save(using=self._db)
        return user
 
    def create_superuser(self, nick_name, email, password, **extra_fields):
        user = self.create_user(nick_name,
            email,
            password,
            **extra_fields
        )
        user.is_staff=True
        user.is_active=True
        user.is_superuser = True
        user.save(using=self._db)
        return user

# 在settings里面指定这个User类为AUTH_USER_MODEL
class User(AbstractBaseUser, PermissionsMixin):
    nick_name = models.CharField(max_length=100, unique=True, db_index=True)
    pwd = models.CharField(max_length=128)
    mobilebind = models.IntegerField(default=0)
    phone = models.CharField(max_length=20)
    say = models.CharField(max_length=255)
    email = models.EmailField(verbose_name='email address',max_length=254)

    is_staff = models.BooleanField('staff status', default=False,
        help_text='flag for log into admin site.')
    is_active = models.BooleanField('active', default=True)
 

    USERNAME_FIELD = 'nick_name'
    REQUIRED_FIELDS = ['email']
    objects = MyUserManager()     # 在这里关联自定义的UserManager

    def get_full_name(self):
        return self.nick_name

    def get_short_name(self):
        return self.nick_name
  
    def __unicode__(self):
        return self.nick_name
    #def is_authenticated(self):  
    #    return True  
  
    ''' 
    # 这个函数可以实现自定义的用户密码检验,除非你想跳过Django的才实现。
    def check_password(self, password):  
        if self.hashed_password(password) == self.pwd:  
            return True
        print 'debug: password(%s), hashed %s, self.pwd %s' % (password, self.hashed_password(password), self.pwd)
        return False
    '''

    '''
    # 这里可以实现自己的密码管理
    def set_password(self, raw_password):
        print 'set_password called'
        self.pwd = self.my_hashed_pwd(raw_password)
        super(User, self).set_password(raw_password)
    '''
    # 如果要自定义表名的话
    class Meta:  
        db_table = "myuser"

# 其他要用到user的地方直接用这个自定义的user就好了
class FriendRelation(models.Model):
    user = models.ForeignKey(User)
    friend = models.IntegerField()

然后在project的settings.py里面加入:

AUTH_USER_MODEL = 'base.User'

接着在base/admin.py(没有就创建)中加入以下代码:

from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from base.models import User  # 这里改成对应的包

class UserCreationForm(forms.ModelForm):
    """A form for creating new users. Includes all the required
    fields, plus a repeated password."""
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ('nick_name', 'pwd', 'email', 'mobilebind', 'say')  # 改成想要的字段

    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("Passwords don't match")
        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super(UserCreationForm, self).save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        if commit:
            user.save()
        return user


class UserChangeForm(forms.ModelForm):
    """A form for updating users. Includes all the fields on
    the user, but replaces the password field with admin's
    password hash display field.
    """
    password = ReadOnlyPasswordHashField()

    class Meta:
        model = User

    def clean_password(self):
        # Regardless of what the user provides, return the initial value.
        # This is done here, rather than on the field, because the
        # field does not have access to the initial value
        return self.initial["password"]


class MyUserAdmin(UserAdmin):
    # The forms to add and change user instances
    form = UserChangeForm
    add_form = UserCreationForm

    # The fields to be used in displaying the User model.
    # These override the definitions on the base UserAdmin
    # that reference specific fields on auth.User.
    list_display = ('nick_name', 'email', 'is_superuser')
    list_filter = ('is_superuser',)
    fieldsets = (
        (None, {'fields': ('nick_name', 'email', 'password')}),
        ('Personal info', {'fields': ('pwd',)}),
        ('Permissions', {'fields': ('is_superuser',)}),
        #('Important dates', {'fields': ('last_login',)}),
    )
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('nick_name', 'pwd', 'email', 'password1', 'password2')}
        ),
    )
    search_fields = ('nick_name', 'email',)
    ordering = ('nick_name', 'email',)
    filter_horizontal = ()

# Now register the new UserAdmin...
admin.site.register(User, MyUserAdmin)
# ... and, since we're not using Django's builtin permissions,
# unregister the Group model from admin.
admin.site.unregister(Group)

通过以上步骤就已经完成了一个自定义的用户模型,需要重新使用./manager.py sync产生数据库。

另外,还可以自定义权限系统,可以参考Django官方文档。

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP