django是基于python的web框架。现在比较流行,有时间具体写django的学习笔记。先直面今天的问题。继承重写django User类。
django自带User、Group和Permission类,分别对应用户、用户组、权限,可以完成登录、权限控制等功能。django虽然不错,但是实际的需求是多种多样的,许多人都需要实现自己特定的用户管理。就我来说,django的登录没问题,问题在于django的权限控制,它的权限控制是基于table的,是粗粒度的,而我做的项目需要更细粒度的权限控制。所以,我需要满足我需求的User、Group、Permission,但是django的User写的不错,直接重写工作量大也怪可惜了。所以我决定重写针对项目的CGroup和Perm(分别对应用户组和权限),继承django原有的User类,添加新的成员perm和cgroup,对应与CGroup和Perm的多对多关系。代码如下:
# coding: utf-8
from django.db import models
from django.forms import ModelForm
from django.contrib.auth.models import User, UserManager
# user is Inherited, perm and cgroup is rewriten
# model
class Perm(models.Model):
name = models.CharField(u"名称", max_length=40, unique=True)
table = models.CharField(u"数据表", max_length=50)
describe = models.CharField(u"描述", max_length=100)
remark = models.CharField(u"备注", null=True, blank=True,max_length=100)
def __unicode__(self):
return self.name
class Meta:
ordering = ['name']
class CGroup(models.Model):
name = models.CharField(u"名称", max_length=50,unique=True)
# level = models.IntegerField(u"等级", unique=True)
describe = models.CharField(u"描述", max_length=100)
perm = models.ManyToManyField(Perm, blank=True, verbose_name=u'权限')
def __unicode__(self):
return self.name
class Meta:
ordering = ['name']
# ordering = ['level']
class User(User):
objects = UserManager()
perm = models.ManyToManyField(Perm, blank=True, verbose_name=u'权限')
cgroup = models.ManyToManyField(CGroup, blank=True, verbose_name=u'用户组')
def has_perm(self,permission):
if self.is_superuser == True:
return True
permlist = self.perm.all()
for perm in permlist:
if perm.name == permission:
return True
grouplist = self.cgroup.all()
for group in grouplist:
permlist = group.perm.all()
for perm in permlist:
if perm.name == permission:
return True
return False
def get_all_permission(self):
permlist = self.perm.all()
if self.is_superuser == True:
permlist = Perm.objects.all()
return permlist
else:
perm_set = set(permlist)
grouplist = user.cgroup.all()
for group in grouplist:
permlist_tmp = group.perm.all()
perm_set_tmp = set(permlist_tmp)
perm_set = perm_set.union(perm_set_tmp)
permlist = list(perm_set)
permlist.sort()
return permlist
# form
class UserForm(ModelForm):
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'password', 'is_active', 'is_superuser', 'last_login', 'date_joined', 'cgroup')
class PermForm(ModelForm):
class Meta:
model = Perm
class CGroupForm(ModelForm):
class Meta:
model = CGroup # over #
关于Perm和CGroup,我是根据我的项目写的,大家根据自己的需求具体实现。重点是User类,其中包括objects = UserManager() ,这样User就可以使用原User的很多方法。此外,针对新的Perm和CGroup,新写了两个方法,has_perm、get_all_permission,分别用来判断用户有无特定权限和获得用户权限列表。
到这里好像一切都结束了,但其实还没有。还有一个问题,我们利用request.user获取的user是一个原有的User的实例,而不是重载的User实例,所以无法获取扩展的字段与方法。哈欠涟涟(http://plq168.blog.163.com/blog/static/531014622010927105232669/)发现了这个问题。为了解决这个问题,他写了自己的登录后台,获取CustomUser(重载后的User)的实例而不是原来User的实例。
我不清楚哈欠涟涟还有没有其他更进一步的需求,不过就我的需求以及他的博文中描述的问题来看,我认为没有这个必要。重写后台较为麻烦。我的做法是,通过request.user.name,获取用户的name,在通过get_object_or_404方法,获取重载后的User。由于User的name的唯一的,所以这种方法是可行的,我采取这种方法做的工程测试也是正常的。
username = request.user.username
user = get_object_or_404(User,username=username)
解决了这个问题后,还有一些细节问题,比如Perm添加。django的Permission可以根据数据表自动添加,所以重写User、Perm、CGroup后,也要注意这个问题。
最后,上一张用户编辑界面的截图(部分)。
转载于:https://blog.51cto.com/speakingbaicai/958331