Django行权限管理(Xadmin+rules级联效果)

行权限配置

xadmin中配置且不需要数据库支持,

安装并配置rules
pip安装:

pip install rules

配置settings.py

# settings.py
INSTALLED_APPS = (
    # ...
    'rules',
)
AUTHENTICATION_BACKENDS = (
    'rules.permissions.ObjectPermissionBackend',
    'django.contrib.auth.backends.ModelBackend',
)

配置models.py

# models.py
class CompanyUser(models.Model):
    users = models.OneToOneField(User, verbose_name='用户名', on_delete=User)
    is_admin = models.BooleanField('是否运营人员', default=False)
    category_code = models.ManyToManyField(user, verbose_name='可管理', max_length=20, blank=True, default='')
    #ForeignKey为单选,ManyToManyField为多选.

    def __str__(self):
        return str(self.users)

    class Meta:
        verbose_name = '管理账号'
        verbose_name_plural = verbose_name
        
        
        
class user(models.Model):
    title = models.CharField(max_length=50, verbose_name="文章标题")
    author = models.CharField(max_length=50, null=True, blank=True, verbose_name='文章作者')
    #category = models.ForeignKey(Category, verbose_name="所属类别", null=True, blank=True, on_delete=Category)(多选时启用)
    content = UEditorField(verbose_name="文章内容", imagePath='static/img/', filePath="static/img/", upload_settings={"imageMaxSize": 1204000}, default='')
    click_num = models.IntegerField(default=0, verbose_name="浏览量", )
    image = models.FileField(max_length=200, verbose_name="文章图片", null=True, blank=True, upload_to='static/img', default=None)
    add_time = models.DateField(default=datetime.now, verbose_name="添加时间")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = '文章信息'
        verbose_name_plural = verbose_name

使用rule

在models的同级目录新增rules.py,配置该app相关的对象权限

# rules.py
#必须将以下内容添加到rules.py文件的顶部,否则在尝试导入django-rules本身时会出现导入错误。
from __future__ import absolute_import 

import rules

# 使用修饰符@rules.predicate自定义predicates(判断),返回True表示有权限,False表示无权限

@rules.predicate
def is_colleague(user, entry):
    if not entry or not hasattr(user, 'companyuser'):
        return False
    return entry.category_code == user.companyuser.category_code


@rules.predicate
def is_admin(user):
    if not hasattr(user, 'companyuser'):
        return False
    return user.companyuser.is_admin


is_admins = is_admin | rules.is_superuser | is_colleague

# 设置Rules

rules.add_rule('can_view_user', is_admins)
rules.add_rule('can_delete_user', is_admins)
rules.add_perm('can_change_user', is_admins)

# 设置Permissions

rules.add_perm('data_import.view_user', is_admins)
rules.add_perm('data_import.delete_user', is_admins)
rules.add_perm('data_import.add_user', is_admins)
rules.add_perm('data_import.change_user', is_admins)

adminx.py设置

必须引用rules文件,权限规则才会生效,对于xadmin,添加from .rules import *即可.

# adminx.py
from __future__ import absolute_import
import xadmin
from xadmin import views
from lice.models import *
from .rules import *


class UserAdmin(object):
    list_display = 'title',
    search_fields = 'title', 'content',
    list_filter = 'category',
    readonly_fields = 'click_num',
    exclude = 'add_time',
    style_fields = {"content": "ueditor"}
    
    def queryset(self):
        qs = super(UserAdmin, self).queryset()
        if self.request.user.is_superuser or is_admin(self.request.user):
            return qs
        try:
            print('-------------------')
            print(qs)#打印一下qs的结果
            print('-------------------')
            print(CompanyUser.objects.get(users=self.request.user).category_code.filter())
            #打印登录账号的可管理内容
            print('-------------------')
            return CompanyUser.objects.get(users=self.request.user).category_code.filter()
        except AttributeError:
            return None
            
            
class CompanyUserAdmin(object):
    pass
            
xadmin.site.register(CompanyUser, CompanyUserAdmin)
xadmin.site.register(user, UserAdmin)

效果展示:
可选用户
可选文章
需先在管理账号里为账号添加可管理内容
列表

大功告成~

行权限配置(多选)

若要达到级联多选效果需要在原基础上修改models.py并添加 views.py\urls.py及js即可实现

新建一个类别模型(可对比上面的模型),并在已有的CompanyUser中添加类别字段

models.py

# models.py
class CompanyUser(models.Model):
    users = models.OneToOneField(User, verbose_name='用户名', on_delete=User)
    is_admin = models.BooleanField('是否运营人员', default=False)
    category = models.ForeignKey(Category, on_delete=Category, verbose_name='可管理分类', max_length=20, null=True, blank=True, default='')
    category_code = models.ManyToManyField(user, verbose_name='可管理文章', max_length=20, null=True, blank=True, default='')
    #ForeignKey为单选,ManyToManyField为多选.

    def __str__(self):
        return str(self.users)

    class Meta:
        verbose_name = '管理账号'
        verbose_name_plural = verbose_name
        
class Category(models.Model):
    name = models.CharField(max_length=20, verbose_name="文章类别")
    add_time = models.DateField(default=datetime.now, verbose_name="添加时间")

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = "类别信息"
        verbose_name_plural = verbose_name

F12找到一级目录和二级目录的select中ID
在这里插入图片描述
在这里插入图片描述

我的一级目录id=id_category,二级目录id=id_category_code
下面开始创建一个新的js文件
并将id替换到js文件中

#名字随便.我的是xadmin.js
# xadmin.js
$('#id_category').change(function () {
    var module = $('#id_category').find('option:selected').val(); //获取父级选中值
    $('#id_category_code')[0].selectize.clearOptions();// 清空子级
    if (module)
        $.ajax({
            type: 'get',
            url: '/select/one_two/?module=' + module,
            data: '',
            async: true,
            beforeSend: function (xhr, settings) {
                xhr.setRequestHeader('X-CSRFToken', '{{ csrf_token }}')
            },
            success: function (data) {
                data = JSON.parse(data.data)//将JSON转换
                console.log(data);
                for (var i = 0; i < data.length; i++) {

                    var test = {text: data[i].fields.title, value: data[i].pk, $order: i + 1}; //遍历数据,拼凑出selectize需要的格式
                    $('#id_category_code')[0].selectize.addOption(test); //添加数据
                }
            },
        })
    else {
        #如果一级目录为分配则遍历所有子目录可选项
        $.ajax({
            type: 'get',
            url: '/select/one_two/?module=all',
            data: '',
            async: true,
            beforeSend: function (xhr, settings) {
                xhr.setRequestHeader('X-CSRFToken', '{{ csrf_token }}')
            },
            success: function (data) {
                data = JSON.parse(data.data)//将JSON转换
                console.log(data);
                for (var i = 0; i < data.length; i++) {

                    var test = {text: data[i].fields.title, value: data[i].pk, $order: i + 1}; //遍历数据,拼凑出selectize需要的格式
                    $('#id_category_code')[0].selectize.addOption(test); //添加数据
                }
            },
        })
    }
})

将js中此行的 ‘title’ 替换为你想要显示的数据库字段名 有两个(20行|40行)

 var test = {text: data[i].fields.title, value: data[i].pk, $order: i + 1}; //遍历数据,拼凑出selectize需要的格式

将写好的js文件放入xadmin\static\xadmin\js中,如图所示
js位置

找到xadmin\widgets.py,将js添加进去(这是xadmin的搜索类)
在这里插入图片描述

添加视图

view.py

#导入serializers
from django.core import serializers
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import View
# 二级联动View函数
class SelectView(LoginRequiredMixin, View):
    def get(self, request):
        # 通过get得到父级选择项
        id_category = request.GET.get('module', '')
        # 筛选出符合父级要求的所有子级,因为输出的是一个集合,需要将数据序列化 serializers.serialize()
        if id_category == 'all':
            id_category_code = serializers.serialize("json", user.objects.all())s
            #通过Ajax请求查询
        else:
            id_category_code = serializers.serialize("json", user.objects.filter(category=int(id_category)))
        # 判断是否存在,输出
        if id_category_code:
            return JsonResponse({'data': id_category_code})

url.py

from users.views import  SelectView
url(r'^select/one_two/', SelectView.as_view(), name='one_two'),

效果展示:

操作方法同上

权限分配

级联效果
成果展示

完成~

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值