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

发布时间:2019-04-09 21:47:48编辑:auto阅读(2394)

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

     

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

     

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

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

关键字