十九、xadmin的进阶开发
1、权限管理
1.1 用户权限
超级用户用户所有的权限,其他的用户默认没有任何权限。
首先添加一个用户Editor1,将职员状态勾选上,否则无法登陆后台,勾选之后登陆后,可以看到该用户没有任何权限:
接下来为该用户添加查看课程和查看章节的权限,需要在xadmin管理员账户下添加:
添加之后,就可以看到有查看章节和查看课程的权限了:
1.2 组权限
添加组编辑部门,赋予如下权限:
然后将用户Editor1添加到这个组中,现在Editor1用户就有了如下权限:
组中的成员不但拥有自己本身的权限外,还拥有组的权限。
2、自定义图标icon
xadmin的图标采用的是第三方CSS样式“font awesome”,可以进官网下载最新的样式替代原本的Http://www.fontawesome.com.cn/
下载完后把里面的“css”和“fonts”两个文件夹拷贝到xadmin的源码(路径:xadmin/static/vendor/font-awesome)里面。
修改课程管理的图标,在官网中找到对应的图标,将class中的内容拷贝下来,在adminx中找到对应的admin进行配置:
1 class CourseAdmin(object):
2 list_display = ['name','desc','detail','degree','learn_times','students']
3 search_fields = ['name', 'desc', 'detail', 'degree', 'students']
4 list_filter = ['name','desc','detail','degree','learn_times','students']
5 model_icon = 'fa fa-book' # 图标样式
刷新后,可以看到图标改变了:
找到合适的图标依次修改其他的admin即可。
3、排序、只读字段和不显示的字段
按点击数倒序排序,点击数不能编辑,不显示收藏人数,以courseAdmin为例:
1 class CourseAdmin(object):
2 list_display = ['name','desc','detail','degree','learn_times','students']
3 search_fields = ['name', 'desc', 'detail', 'degree', 'students']
4 list_filter = ['name','desc','detail','degree','learn_times','students']
5 model_icon = 'fa fa-book' # 图标样式
6 ordering = ['-click_nums'] # 排序
7 readonly_fields = ['click_nums'] # 只读字段
8 exclude = ['fav_nums'] # 不显示字段
4、inlines添加数据
目前在添加课程的页面没法直接去添加章节和课程资源,我们可以用inlines去实现这一功能:
1 class LessonInline(object):
2 model = Lesson
3 extra = 0
4
5
6 class CourseResourcsInline(object):
7 model = CourseResourse
8 extra = 0
9
10
11 class CourseAdmin(object):
12 list_display = ['name','desc','detail','degree','learn_times','students']
13 search_fields = ['name', 'desc', 'detail', 'degree', 'students']
14 list_filter = ['name','desc','detail','degree','learn_times','students']
15 model_icon = 'fa fa-book' # 图标样式
16 ordering = ['-click_nums'] # 排序
17 readonly_fields = ['click_nums'] # 只读字段
18 exclude = ['fav_nums'] # 不显示字段
19 inlines = [LessonInline, CourseResourcsInline]
效果如下:
5、一张表分两个model来管理
课程里面分为轮播课程和不是轮播课程两种类型,我们可以分开来进行管理。在course/models.py里面新增一个model:
1 class BannerCourse(Course):
2 """轮播课程"""
3 class Meta:
4 verbose_name = '轮播课程'
5 verbose_name_plural = verbose_name
6 proxy = True # 设为True,就不会再生成一张表,同时还具有model的作用
然后在adminx.py中注册这个model:
1 class CourseAdmin(object):
2 list_display = ['name','desc','detail','degree','learn_times','students']
3 search_fields = ['name', 'desc', 'detail', 'degree', 'students']
4 list_filter = ['name','desc','detail','degree','learn_times','students']
5 model_icon = 'fa fa-book' # 图标样式
6 ordering = ['-click_nums'] # 排序
7 readonly_fields = ['click_nums'] # 只读字段
8 exclude = ['fav_nums'] # 不显示字段
9 inlines = [LessonInline, CourseResourcsInline]
10
11 def queryset(self):
12 # 重载queryset方法,来过滤出我们想要的数据的
13 qs = super(CourseAdmin, self).queryset()
14 qs = qs.filter(is_banner=False)
15 return qs
16
17 xadmin.site.reGISter(Course, CourseAdmin)
18
19
20 class BannerCourseAdmin(object):
21 list_display = ['name', 'desc', 'detail', 'degree', 'learn_times', 'students']
22 search_fields = ['name', 'desc', 'detail', 'degree', 'students']
23 list_filter = ['name', 'desc', 'detail', 'degree', 'learn_times', 'students']
24 model_icon = 'fa fa-book' # 图标样式
25 ordering = ['-click_nums'] # 排序
26 readonly_fields = ['click_nums'] # 只读字段
27 exclude = ['fav_nums'] # 不显示字段
28 inlines = [LessonInline, CourseResourcsInline]
29
30 def queryset(self):
31 # 重载queryset方法,来过滤出我们想要的数据的
32 qs = super(BannerCourseAdmin, self).queryset()
33 qs = qs.filter(is_banner=True)
34 return qs
35
36 xadmin.site.register(BannerCourse, BannerCourseAdmin)
完成之后,刷新后台页面可以看到多了轮播课程,可以对轮播课程和课程进行分开管理:
6、其他功能
6.1 列表内对字段进行编辑
1 class CourseAdmin(object):
2 list_display = ['name','desc','detail','degree','learn_times','students']
3 search_fields = ['name', 'desc', 'detail', 'degree', 'students']
4 list_filter = ['name','desc','detail','degree','learn_times','students']
5 model_icon = 'fa fa-book' # 图标样式
6 ordering = ['-click_nums'] # 排序
7 readonly_fields = ['click_nums'] # 只读字段
8 exclude = ['fav_nums'] # 不显示字段
9 inlines = [LessonInline, CourseResourcsInline]
10 list_editable = ['degree', 'desc'] # 允许修改的字段
11
12 def queryset(self):
13 # 重载queryset方法,来过滤出我们想要的数据的
14 qs = super(CourseAdmin, self).queryset()
15 qs = qs.filter(is_banner=False)
16 return qs
6.2 自定义函数作为列显示
在course的model中添加后台显示章节名称的方法:
1 class Course(models.Model):
2 """课程"""
3 DEGREE_CHOICES = (
4 ('cj', '初级'),
5 ('zj', '中级'),
6 ('gj', '高级')
7 )
8
9 name = models.CharField('课程名', max_length=50)
10 desc = models.CharField('课程描述', max_length=300)
11 detail = models.TextField('课程详情')
12 degree = models.CharField('课程难度', choices=DEGREE_CHOICES, max_length=2)
13 learn_times = models.IntegerField('学习时长(分钟数)', default=0)
14 students = models.IntegerField('学习人数', default=0)
15 fav_nums = models.IntegerField('收藏人数', default=0)
16 click_nums = models.IntegerField('点击数', default=0)
17 image = models.ImageField('封面图', upload_to='courses/%Y/%m', max_length=100)
18 course_org = models.ForeignKey(CourseOrg, verbose_name='所属机构', on_delete=models.CASCADE, null=True, blank=True)
19 cateGory = models.CharField('课程类别', max_length=20, default='')
20 tag = models.CharField('标签', max_length=10, default='')
21 teacher = models.ForeignKey(Teacher, verbose_name='机构讲师', on_delete=models.CASCADE, null=True, blank=True)
22 courseneed_know = models.CharField('课程须知', max_length=300, default='')
23 teacher_tellyou = models.CharField('老师告诉你', max_length=300, default='')
24 is_banner = models.BooleanField('是否轮播', default=False)
25 add_time = models.DateTimeField('添加时间', default=datetime.now)
26
27 class Meta:
28 verbose_name = '课程'
29 verbose_name_plural = verbose_name
30
31 # 获取章节数
32 def get_zj_nums(self):
33 return self.lesson_set.all().count()
34
35 get_zj_nums.short_description = '章节数' # 后台显示的名称
36
37 # 获取学习用户
38 def get_learn_users(self):
39 return self.usercourse_set.all()[:5]
40
41 # 获取章节
42 def get_course_lesson(self):
43 return self.lesson_set.all()
44
45 def __str__(self):
46 return self.name
然后在adminx.py中显示列的字段list_display中添加get_zj_nums:
1 class CourseAdmin(object):
2 list_display = ['name','desc','detail','degree','learn_times','students', 'get_zj_nums']
3 search_fields = ['name', 'desc', 'detail', 'degree', 'students']
4 list_filter = ['name','desc','detail','degree','learn_times','students']
5 model_icon = 'fa fa-book' # 图标样式
6 ordering = ['-click_nums'] # 排序
7 readonly_fields = ['click_nums'] # 只读字段
8 exclude = ['fav_nums'] # 不显示字段
9 inlines = [LessonInline, CourseResourcsInline]
10 list_editable = ['degree', 'desc'] # 允许修改的字段
11
12 def queryset(self):
13 # 重载queryset方法,来过滤出我们想要的数据的
14 qs = super(CourseAdmin, self).queryset()
15 qs = qs.filter(is_banner=False)
16 return qs
6.3 显示自定义的html代码
在course的model中添加跳转的html代码函数:
1 class Course(models.Model):
2 """课程"""
3 DEGREE_CHOICES = (
4 ('cj', '初级'),
5 ('zj', '中级'),
6 ('gj', '高级')
7 )
8
9 name = models.CharField('课程名', max_length=50)
10 desc = models.CharField('课程描述', max_length=300)
11 detail = models.TextField('课程详情')
12 degree = models.CharField('课程难度', choices=DEGREE_CHOICES, max_length=2)
13 learn_times = models.IntegerField('学习时长(分钟数)', default=0)
14 students = models.IntegerField('学习人数', default=0)
15 fav_nums = models.IntegerField('收藏人数', default=0)
16 click_nums = models.IntegerField('点击数', default=0)
17 image = models.ImageField('封面图', upload_to='courses/%Y/%m', max_length=100)
18 course_org = models.ForeignKey(CourseOrg, verbose_name='所属机构', on_delete=models.CASCADE, null=True, blank=True)
19 category = models.CharField('课程类别', max_length=20, default='')
20 tag = models.CharField('标签', max_length=10, default='')
21 teacher = models.ForeignKey(Teacher, verbose_name='机构讲师', on_delete=models.CASCADE, null=True, blank=True)
22 courseneed_know = models.CharField('课程须知', max_length=300, default='')
23 teacher_tellyou = models.CharField('老师告诉你', max_length=300, default='')
24 is_banner = models.BooleanField('是否轮播', default=False)
25 add_time = models.DateTimeField('添加时间', default=datetime.now)
26
27 class Meta:
28 verbose_name = '课程'
29 verbose_name_plural = verbose_name
30
31 # 获取章节数
32 def get_zj_nums(self):
33 return self.lesson_set.all().count()
34 get_zj_nums.short_description = '章节数' # 后台显示的名称
35
36 # 获取学习用户
37 def get_learn_users(self):
38 return self.usercourse_set.all()[:5]
39
40 # 获取章节
41 def get_course_lesson(self):
42 return self.lesson_set.all()
43
44 # 跳转
45 def go_to(self):
46 # mark_safe之后就不会转义
47 return mark_safe('<a href="https://www.cnblogs.com/Sweltering/">跳转</a>')
48 go_to.short_description = '跳转'
49
50 def __str__(self):
51 return self.name
然后在adminx.py中显示列的字段list_display中添加go_to:
1 class CourseAdmin(object):
2 list_display = ['name','desc','detail','degree','learn_times','students', 'get_zj_nums', 'go_to']
3 search_fields = ['name', 'desc', 'detail', 'degree', 'students']
4 list_filter = ['name','desc','detail','degree','learn_times','students']
5 model_icon = 'fa fa-book' # 图标样式
6 ordering = ['-click_nums'] # 排序
7 readonly_fields = ['click_nums'] # 只读字段
8 exclude = ['fav_nums'] # 不显示字段
9 inlines = [LessonInline, CourseResourcsInline]
10 list_editable = ['degree', 'desc'] # 允许修改的字段
11
12 def queryset(self):
13 # 重载queryset方法,来过滤出我们想要的数据的
14 qs = super(CourseAdmin, self).queryset()
15 qs = qs.filter(is_banner=False)
16 return qs
6.4 refresh定时刷新工具
在adminx中添加refresh_times:
1 class CourseAdmin(object):
2 list_display = ['name','desc','detail','degree','learn_times','students', 'get_zj_nums', 'go_to']
3 search_fields = ['name', 'desc', 'detail', 'degree', 'students']
4 list_filter = ['name','desc','detail','degree','learn_times','students']
5 model_icon = 'fa fa-book' # 图标样式
6 ordering = ['-click_nums'] # 排序
7 readonly_fields = ['click_nums'] # 只读字段
8 exclude = ['fav_nums'] # 不显示字段
9 inlines = [LessonInline, CourseResourcsInline]
10 list_editable = ['degree', 'desc'] # 允许修改的字段
11 refresh_times = [3, 5] # 自动刷新
12
13 def queryset(self):
14 # 重载queryset方法,来过滤出我们想要的数据的
15 qs = super(CourseAdmin, self).queryset()
16 qs = qs.filter(is_banner=False)
17 return qs
6.5 字段联动
当添加一门课程的时候,希望课程机构里面的课程数 +1,需要重写xadmin的save_models方法:
1 class CourseAdmin(object):
2 list_display = ['name','desc','detail','degree','learn_times','students', 'get_zj_nums', 'go_to']
3 search_fields = ['name', 'desc', 'detail', 'degree', 'students']
4 list_filter = ['name','desc','detail','degree','learn_times','students']
5 model_icon = 'fa fa-book' # 图标样式
6 ordering = ['-click_nums'] # 排序
7 readonly_fields = ['click_nums'] # 只读字段
8 exclude = ['fav_nums'] # 不显示字段
9 inlines = [LessonInline, CourseResourcsInline]
10 list_editable = ['degree', 'desc'] # 允许修改的字段
11 refresh_times = [3, 5] # 自动刷新
12
13 def queryset(self):
14 # 重载queryset方法,来过滤出我们想要的数据的
15 qs = super(CourseAdmin, self).queryset()
16 qs = qs.filter(is_banner=False)
17 return qs
18
19 def save_models(self):
20 # obj实际是一个course对象
21 obj = self.new_obj
22 # 如果这里不保存,新增课程,统计的课程数会少一个
23 obj.save()
24 if obj.course_org is not None:
25 # 找到添加的课程的课程机构
26 course_org = obj.course_org
27 # 课程机构的课程数量等于添加课程后的数量
28 course_org.course_nums = Course.objects.filter(course_org=course_org).count()
29 course_org.save()
7、富文本编辑器Ueditor
首先在GitHub上下载富文本编辑器Ueditor:https://github.com/twz915/DjangoUeditor3/
下载解压将DjangoUeditor文件拷贝到项目根目录下:
在settings.py中注册app:
1 INSTALLED_APPS = [
2 'DjangoUeditor',
3 ]
然后在urls.py中配置url:
1 urlpatterns = [
2 path('ueditor/',include('DjangoUeditor.urls' )), # 富文本编辑器
3 ]
修改course的model中detail课程详情字段为富文本字段:
1 class Course(models.Model):
2 """课程"""
3 DEGREE_CHOICES = (
4 ('cj', '初级'),
5 ('zj', '中级'),
6 ('gj', '高级')
7 )
8
9 name = models.CharField('课程名', max_length=50)
10 desc = models.CharField('课程描述', max_length=300)
11 # detail = models.TextField('课程详情')
12 detail = UEditorField(verbose_name=u'课程详情', width=600, height=300, imagePath="courses/ueditor/",
13 filePath="courses/ueditor/", default='')
14 degree = models.CharField('课程难度', choices=DEGREE_CHOICES, max_length=2)
15 learn_times = models.IntegerField('学习时长(分钟数)', default=0)
16 students = models.IntegerField('学习人数', default=0)
17 fav_nums = models.IntegerField('收藏人数', default=0)
18 click_nums = models.IntegerField('点击数', default=0)
19 image = models.ImageField('封面图', upload_to='courses/%Y/%m', max_length=100)
20 course_org = models.ForeignKey(CourseOrg, verbose_name='所属机构', on_delete=models.CASCADE, null=True, blank=True)
21 category = models.CharField('课程类别', max_length=20, default='')
22 tag = models.CharField('标签', max_length=10, default='')
23 teacher = models.ForeignKey(Teacher, verbose_name='机构讲师', on_delete=models.CASCADE, null=True, blank=True)
24 courseneed_know = models.CharField('课程须知', max_length=300, default='')
25 teacher_tellyou = models.CharField('老师告诉你', max_length=300, default='')
26 is_banner = models.BooleanField('是否轮播', default=False)
27 add_time = models.DateTimeField('添加时间', default=datetime.now)
28
29 class Meta:
30 verbose_name = '课程'
31 verbose_name_plural = verbose_name
32
33 # 获取章节数
34 def get_zj_nums(self):
35 return self.lesson_set.all().count()
36 get_zj_nums.short_description = '章节数' # 后台显示的名称
37
38 # 获取学习用户
39 def get_learn_users(self):
40 return self.usercourse_set.all()[:5]
41
42 # 获取章节
43 def get_course_lesson(self):
44 return self.lesson_set.all()
45
46 # 跳转
47 def go_to(self):
48 # mark_safe之后就不会转义
49 return mark_safe('<a href="https://www.cnblogs.com/Sweltering/">跳转</a>')
50 go_to.short_description = '跳转'
51
52 def __str__(self):
53 return self.name
在xadmin/plugins下新建ueditor.py文件:
1 import xadmin
2 from xadmin.views import BaseAdminPlugin, CreateAdminView, ModelFORMAdminView, UpdateAdminView
3 from DjangoUeditor.models import UEditorField
4 from DjangoUeditor.widgets import UEditorWidget
5 from django.conf import settings
6
7
8 class XadminUEditorWidget(UEditorWidget):
9 def __init__(self, **kwargs):
10 self.ueditor_options = kwargs
11 self.Media.js = None
12 super(XadminUEditorWidget,self).__init__(kwargs)
13
14
15 class UeditorPlugin(BaseAdminPlugin):
16
17 def get_field_style(self, attrs, db_field, style, **kwargs):
18 if style == 'ueditor':
19 if isinstance(db_field, UEditorField):
20 widget = db_field.formfield().widget
21 param = {}
22 param.update(widget.ueditor_settings)
23 param.update(widget.attrs)
24 return {'widget':XadminUEditorWidget(**param)}
25 return attrs
26
27 def block_extrahead(self, context, nodes):
28 js = '<script type="text/javascript" src="%s"></script>' %(settings.STATIC_URL + "ueditor/ueditor.config.js")
29 js += '<script type="text/javascript" src="%s"></script>' %(settings.STATIC_URL + "ueditor/ueditor.all.min.js")
30 nodes.append(js)
31
32 xadmin.site.register_plugin(UeditorPlugin, UpdateAdminView)
33 xadmin.site.register_plugin(UeditorPlugin, CreateAdminView)
在xadmin/plugins/__init__.py文件下注册ueditor插件:
1 PLUGINS = (
2 'ueditor',
3 )
然后在course/adminx.py中使style_fields在后台编辑中使用富文本:
1 class CourseAdmin(object):
2 list_display = ['name','desc','detail','degree','learn_times','students', 'get_zj_nums', 'go_to']
3 search_fields = ['name', 'desc', 'detail', 'degree', 'students']
4 list_filter = ['name','desc','detail','degree','learn_times','students']
5 model_icon = 'fa fa-book' # 图标样式
6 ordering = ['-click_nums'] # 排序
7 readonly_fields = ['click_nums'] # 只读字段
8 exclude = ['fav_nums'] # 不显示字段
9 inlines = [LessonInline, CourseResourcsInline]
10 list_editable = ['degree', 'desc'] # 允许修改的字段
11 refresh_times = [3, 5] # 自动刷新
12 style_fields = {"detail": "ueditor"} # detail就是要显示为富文本的字段名
13
14 def queryset(self):
15 # 重载queryset方法,来过滤出我们想要的数据的
16 qs = super(CourseAdmin, self).queryset()
17 qs = qs.filter(is_banner=False)
18 return qs
19
20 def save_models(self):
21 # obj实际是一个course对象
22 obj = self.new_obj
23 # 如果这里不保存,新增课程,统计的课程数会少一个
24 obj.save()
25 if obj.course_org is not None:
26 # 找到添加的课程的课程机构
27 course_org = obj.course_org
28 # 课程机构的课程数量等于添加课程后的数量
29 course_org.course_nums = Course.objects.filter(course_org=course_org).count()
30 course_org.save()
修改前端course-detail.html页面课程详情已富文本的形式显示,在模板中必须关闭Django的自动转义才能正常显示:
后台课程详情可以富文本进行编辑:
前端课程详情以富文本形式进行展示:
至此,整个项目已经编写完成,如有考虑不到之处请指出,希望能够共同学习!!!!
0