(项目)在线教育平台(十三)

2018-11-26 07:59:02来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

十九、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的自动转义才能正常显示:

 

   后台课程详情可以富文本进行编辑:

 

   前端课程详情以富文本形式进行展示:

  至此,整个项目已经编写完成,如有考虑不到之处请指出,希望能够共同学习!!!!

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:django+mysql的使用

下一篇:Python爬虫基础(一)——HTTP