django admin实现后台多用户隔离

很多人说django自带的后台只能用来做管理,其实简单的多用户发布需求还是可以用自带的admin模块来做的。核心是使用 request.user 获取当前登录用户,然后根据用户筛选后台显示内容。

复杂的用户权限管理使用django-guardian等组件

模拟了一个根据用户每天输入的数据,生成可视化报表的项目。预想的是根据不同的报表类型,预设不同的数据模板。前端请求的时候发送报表类型和数据范围用户等信息到后端。后端返回数据后交给前端echart处理。

花了整个下午才完成基本的后台,因为目的是实现多用户,后面的部分有空再去写。

  • 先设置一般用户的group,配置好权限,所有新建用户都是用一般的权限。权限设置看文档
  • 隔离列表页
    列表页隔离,使用get_queryset方法,这个比较好实现,资料也多
  • class NoteAdmin(admin.ModelAdmin):
        def get_queryset(self,request):
            qs = super(NoteAdmin,self).get_queryset(request)
            if request.user.is_superuser:
                return qs
            # 此处user为当前model的related object的related object, 正常的外键只要filter(user=request.user)
            return qs.filter(fordata__user=request.user)
        list_display = ('title','fordata')
        search_fields = ('title','fordata')
    
  • 隔离增加和修改数据时显示的related object项目
  • ![HTZMQ)4(7BXHAD`K~F]QSLR.png](http://upload-images.jianshu.io/upload_images/923222-cb82053c32efc77e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    创建和修改model时,会显示关联的外键的所有的值,比如显示出所有的用户来了。使用get_form方法隐藏外键字段(例如user),save_model设置user默认值,也别忘了列表页的筛选get_queryset

    class CustomTypeAdmin(admin.ModelAdmin):
        def save_model(self,request,obj,form,change):
            obj.user = request.user
            obj.save()
        def get_form(self,request,obj=None,**kwargs):
            self.exclude = ("user",)
            form = super(CustomTypeAdmin,self).get_form(request, obj, **kwargs)
            return form
        fields = ('typename','ordernum')
        list_display = ('typename','ordernum')
        list_editable = ('ordernum',)
        def get_queryset(self,request):
            qs = super(CustomTypeAdmin,self).get_queryset(request)
            if request.user.is_superuser:
                return qs
            return qs.filter(user=request.user)
    

    附:最基本的几个model代码

    class CustomType(models.Model):
        typename = models.CharField(max_length=50,verbose_name='报表名')
        user = models.ForeignKey(User,verbose_name='用户',on_delete=models.CASCADE)
        ordernum = models.IntegerField()
        def __unicode__(self):
            return self.typename
        class Meta:
            verbose_name = '报告分类'
            verbose_name_plural = '报告分类'
    
    class DailyData(models.Model):
        add_date = models.DateField(default=timezone.now,verbose_name='日期')
        record = models.FloatField(verbose_name='数据')
        user = models.ForeignKey(User,verbose_name='用户',on_delete=models.CASCADE)
        type = models.ForeignKey(CustomType,verbose_name='类型',on_delete=models.CASCADE)
        def __unicode__(self):
            return '%s / %s / %s' % (self.add_date.strftime('%Y-%m-%d'),self.type,self.record)
        class Meta:
            verbose_name = '数据'
            verbose_name_plural = '数据'
    
    class Note(models.Model):
        title = models.CharField(max_length=50,verbose_name='简述')
        note = models.TextField(verbose_name='备注')
        fordata = models.ForeignKey(DailyData,verbose_name="备注给",on_delete=models.CASCADE)
        def __unicode__(self):
            return self.title