您现在的位置是: 网站首页 >Django >Django2.0.8+xadmin2实现在线学习网站 Django
【Django在线教育平台】12.课程列表及详情展示
admin2019年6月4日 14:06 【Django | Html | JQuery 】 1465人已围观
Django2.0.8+xadmin2实现在线学习网站简介 Django2.0.8+xadmin2实现在线学习网站,课程、讲师、机构、用户收藏功能。GitHub地址:https://github.com/xyliurui/OnlineLearningPlatform ;Django版本:2.0.8
# 课程相关功能实现 ## 创建course的url 在courses应用下创建一个urls.py文件,用于放置课程相关的url ```python from django.urls import path, re_path app_name = 'courses' urlpatterns = [ # 课程相关url ] ``` 修改主urls,增加course命名空间 ```python urlpatterns = [ path('admin/', admin.site.urls), path('xadmin/', xadmin.site.urls), path('', TemplateView.as_view(template_name='index.html'), name='index'), # path('login/', TemplateView.as_view(template_name='login.html'), name='login'), # path('login/', user_login, name='login'), path('login/', LoginView.as_view(), name='login'), # 基于类方法实现登录,这里是调用它的方法 path('register/', RegisterView.as_view(), name='register'), re_path('register/active/(?P<active_code>.*)/', ActiveUserView.as_view(), name='user_active'), # 激活 path('captcha/', include('captcha.urls')), path('forgetpwd/', ForgetPwdView.as_view(), name='forgetpwd'), # 忘记密码 re_path('forgetpwd/reset/(?P<active_code>.*)/', RestpwdView.as_view(), name='resetpwd'), # 密码重置验证 path('modify_pwd/', ModifypwdView.as_view(), name="modify_pwd"), # 密码修改 # path('org/list/', OrgListView.as_view(), name="org_list"), # 机构列表 # 课程机构url配置 path('org/', include('organization.urls', namespace='org')), # 课程相关功能url path('course/', include('courses.urls', namespace='course')), ] ``` ## 课程列表 ### 创建课程列表视图 有排序、分页功能 ```python from django.shortcuts import render from django.views.generic.base import View from django.utils import timezone from pure_pagination import Paginator, EmptyPage, PageNotAnInteger from .models import Course class CourseListView(View): def get(self, request): all_degree = list(map(lambda x: {'code': x[0], 'explain': x[1]}, Course.DEGREE_CHOICES)) # 显示难度等级 all_course = Course.objects.all().order_by('-add_time') # 默认按照时间排序 degree_code = request.GET.get('degree', '') if degree_code: all_course = all_course.filter(degree=degree_code) sort = request.GET.get('sort', '') if sort: if sort == 'fav': all_course = all_course.order_by('-fav_nums') # 收藏人数排序 elif sort == 'click': all_course = all_course.order_by('-click_nums') # 点击数排序 elif sort == 'students': all_course = all_course.order_by('-students') # 按学习人数排序 course_nums = all_course.count() # 课程筛选后的数量 # 分页 try: page = request.GET.get('page', 1) except PageNotAnInteger: page = 1 # 这里指从all_course中取8个出来,每页显示8个 p = Paginator(all_course, 8, request=request) all_course_page = p.page(page) hot_course = Course.objects.all().order_by('-students')[:3] # 热门课程选择3个显示 # 标记当前页,用于页面选中active current_access_url = 'course' # 当前时间 time_now = timezone.now() return render(request, 'course-list.html', locals()) ``` ### 课程列表url ```python from django.urls import path, re_path from .views import CourseListView app_name = 'courses' urlpatterns = [ # 课程相关url path('list/', CourseListView.as_view(), name='course_list'), ] ``` ### 课程列表模板course-list.html 在courses应用下创建course-list.html用于展示课程列表,需要继承base.html ```html <ul> <li><b>难度等级</b></li> <li><a href="?sort={{ sort }}°ree=" {% ifequal degree_code '' %} style="color: #BEBEBE" {% endifequal %}> 全部 </a></li> {% for degree in all_degree %} <li><a href="?sort={{ sort }}°ree={{ degree.code }}" {% ifequal degree_code degree.code %} style="color: #BEBEBE" {% endifequal %}> {{ degree.explain }} </a></li> {% endfor %} </ul> <h2>课程列表 <small>(共{{ course_nums }}条)</small> </h2> <ul> <!-- Short List --> <li> <p><a href="?sort=°ree={{ degree_code }}" {% ifequal sort '' %} style="font-weight: bold" {% endifequal %}> 最新 </a></p> </li> <li> <p><a href="?sort=students°ree={{ degree_code }}" {% ifequal sort 'students' %} style="color: #BEBEBE" {% endifequal %}> 学习人数 ↓</a></p> </li> <li> <p><a href="?sort=fav°ree={{ degree_code }}" {% ifequal sort 'fav' %} style="color: #BEBEBE" {% endifequal %}> 收藏人数 ↓</a></p> </li> <li> <p><a href="?sort=click°ree={{ degree_code }}" {% ifequal sort 'click' %} style="color: #BEBEBE" {% endifequal %}>点击数 ↓</a></p> </li> </ul> {% for course in all_course_page.object_list %} <!-- Product --> <a href="{% url 'course:course_detail' course.id %}"> <div class="product"> <article> <img class="img-responsive" style="height: 160px; width: auto;" src="{% if course.image %}{{ course.image.url }}{% else %}{% static 'platform/images/default-course.png' %}{% endif %}" alt=""> {% if course.add_time|date:"Y-m-d" == time_now|date:"Y-m-d" %}<span class="new-tag">今天</span>{% endif %} <!-- Content --> <span class="tag">{{ course.course_org.name }}</span> <div class="tittle" style="min-height: 2px;">{{ course.name }}</div> <!-- Reviews --> <p class="rev"> <i class="fa fa-group" title="学习人数"></i> {{ course.students }} <span class="margin-left-36"><i class="fa fa-star" title="收藏人数"></i> {{ course.fav_nums }}</span> <span class="margin-left-36"><i class="fa fa-mouse-pointer" title="点击数"></i> {{ course.click_nums }}</span> </p> <div class="price">课时: {{ course.learn_times }}分钟</div> </article> </div> </a> {% endfor %} <ul class="container pagination padding-left-20"> {% if all_course_page.has_previous %} <li><a href="?{{ all_course_page.previous_page_number.querystring }}" aria-label="Previous"> <i class="fa fa-angle-left"></i> </a></li> {% endif %} {% for page in all_course_page.pages %} {% if page %} {% ifequal page all_course_page.number %} <li><a class="active" href="?{{ page.querystring }}">{{ page }}</a></li> {% else %} <li><a href="?{{ page.querystring }}">{{ page }}</a></li> {% endifequal %} {% else %} <li><a href="">...</a></li> {% endif %} {% endfor %} {% if all_course_page.has_next %} <li><a href="?{{ all_course_page.next_page_number.querystring }}" aria-label="Next"> <i class="fa fa-angle-right"></i> </a></li> {% endif %} </ul> {# <span>{{ course.degree }}</span>#} <span>{{ course.get_degree_display }}</span> ``` 这里的degree我们在数据库中填写的是字母。如何显示为中文。 `get_degree_display` degree是字段名。专门用于`choice`字段显示 ![BLOG_20190604_140741_27](/media/blog/images/2019/06/BLOG_20190604_140741_27.png "博客图集BLOG_20190604_140741_27.png") ## 课程详情页 ### 创建课程详情模板course-detail.html 创建course-detail.html同样继承base.html ```html <h5>{{ course.name }}</h5> <p class="rev"><i class="fa fa-info"></i> {{ course.desc }}</p> <div class="row"> <div class="col-sm-6">难度:<span class="price">{{ course.get_degree_display }}</span></div> <div class="col-sm-6"> <p>课时:<span class="in-stock">{{ course.learn_times }} 分钟</span></p> </div> </div> <!-- List Details --> <ul class="bullet-round-list"> <li>学习人数:{{ course.students }}</li> <li>收 藏 数:{{ course.fav_nums }}</li> <li>点 击 数:{{ course.click_nums }}</li> <li>章 节 数:</li> </ul> <ul class="cmp-list"> <li><a href="#."><i class="fa fa-heart"></i> 添加收藏</a></li> </ul> <a href="#." class="btn-round"> 开始学习</a></div> ``` ![BLOG_20190604_140732_78](/media/blog/images/2019/06/BLOG_20190604_140732_78.png "博客图集BLOG_20190604_140732_78.png") ### 课程详情视图CourseDetailView(View) ```python # 单个课程详情 class CourseDetailView(View): def get(self, request, course_id): course = Course.objects.get(id=course_id) # 标记当前页,用于页面选中active current_access_url = 'course' return render(request, 'course-detail.html', locals()) ``` ### 课程详情url ```python from .views import CourseListView, CourseDetailView app_name = 'courses' urlpatterns = [ # 课程相关url path('list/', CourseListView.as_view(), name='course_list'), re_path('id/(?P<course_id>\d+)/detail/', CourseDetailView.as_view(), name="course_detail"), ] ``` ### 获取课程章节数 ```python # 课程信息表 class Course(models.Model): DEGREE_CHOICES = ( ("cj", "初级"), ("zj", "中级"), ("gj", "高级") ) name = models.CharField(max_length=50, verbose_name='课程名') desc = models.CharField(max_length=300, verbose_name='课程描述') # 后面会改为富文本 detail = models.TextField(verbose_name='课程详情') degree = models.CharField(max_length=3, choices=DEGREE_CHOICES, verbose_name='课程难度') learn_times = models.IntegerField(default=0, verbose_name='学习时长(分钟数)') # 点击开始学习后记录学习人数 students = models.IntegerField(default=0, verbose_name='学习人数') fav_nums = models.IntegerField(default=0, verbose_name='收藏人数') image = models.ImageField(upload_to='course/%Y/%m', max_length=100, blank=True, null=True, verbose_name='封面图(160*160px)') # 点击到课程信息界面即需要记录点击数 click_nums = models.IntegerField(default=0, verbose_name='点击数') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') course_org = models.ForeignKey(CourseOrg, null=True, blank=True, related_name='courses', on_delete=models.CASCADE, verbose_name='所属机构') class Meta: verbose_name = verbose_name_plural = '课程' def get_lesson_nums(self): # 获取课程章节数,如果章节模型中未定义关联名称(related_name)则直接使用字段名_set来获取 return self.lesson_set.all().count() def __str__(self): return self.name ``` 然后再模板中可使用`{{ course.get_lesson_nums }}`获取章节数 ### 课程模型添加类别信息 创建课程类别模型,且课程模型中外键引入 ```python # 课程类别 class Category(models.Model): name = models.CharField(max_length=50, verbose_name='课程类别') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') class Meta: verbose_name = verbose_name_plural = '课程类别' def __str__(self): return self.name # 课程信息表 class Course(models.Model): DEGREE_CHOICES = ( ("cj", "初级"), ("zj", "中级"), ("gj", "高级") ) name = models.CharField(max_length=50, verbose_name='课程名') desc = models.CharField(max_length=300, verbose_name='课程描述') # 后面会改为富文本 detail = models.TextField(verbose_name='课程详情') degree = models.CharField(max_length=3, choices=DEGREE_CHOICES, verbose_name='课程难度') learn_times = models.IntegerField(default=0, verbose_name='学习时长(分钟数)') # 点击开始学习后记录学习人数 students = models.IntegerField(default=0, verbose_name='学习人数') fav_nums = models.IntegerField(default=0, verbose_name='收藏人数') image = models.ImageField(upload_to='course/%Y/%m', max_length=100, blank=True, null=True, verbose_name='封面图(160*160px)') # 点击到课程信息界面即需要记录点击数 click_nums = models.IntegerField(default=0, verbose_name='点击数') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') course_org = models.ForeignKey(CourseOrg, null=True, blank=True, related_name='courses', on_delete=models.CASCADE, verbose_name='所属机构') category = models.ForeignKey(Category, null=True, blank=True, on_delete=models.SET_NULL, related_name='courses', verbose_name='课程类别') # 课程类别删除后课程该字段设置为null class Meta: verbose_name = verbose_name_plural = '课程' def get_lesson_nums(self): # 获取课程章节数,如果章节模型中未定义关联名称(related_name)则直接使用字段名_set来获取 return self.lesson_set.all().count() def __str__(self): return self.name ``` 执行同步 ```python manage.py@DjangoOnlineLearningPlatform > makemigrations courses manage.py@DjangoOnlineLearningPlatform > migrate courses ``` adminx.py中添加Category模型管理 ```python class CategoryAdmin(object): list_display = ['name', 'add_time'] xadmin.site.register(Category, CategoryAdmin) ``` 模板中获取类别信息 ```html <li>课程分类:{{ course.category.name }}</li> ``` ### 课程点击数增加 `course.save(update_fields=['click_nums'])`只更新点击数字段 ```python # 单个课程详情 class CourseDetailView(View): def get(self, request, course_id): course = Course.objects.get(id=course_id) # 增加课程点击数 course.click_nums += 1 course.save(update_fields=['click_nums']) # 标记当前页,用于页面选中active current_access_url = 'course' return render(request, 'course-detail.html', locals()) ``` ### 课程所在机构的讲师数量 方法一: ```python # 课程机构信息 class CourseOrg(models.Model): ORG_CHOICES = ( ("pxjg", "培训机构"), ("gx", "高校"), ("gr", "个人"), ) name = models.CharField(max_length=50, verbose_name='机构名称') desc = models.TextField(verbose_name='机构描述') category = models.CharField(choices=ORG_CHOICES, max_length=10, default='pxjg', verbose_name='机构类别') click_nums = models.IntegerField(default=0, verbose_name='点击数') fav_nums = models.IntegerField(default=0, verbose_name='收藏数') students = models.IntegerField(default=0, verbose_name='学习人数') course_nums = models.IntegerField(default=0, verbose_name='课程数') image = models.ImageField(upload_to='org/%Y/%m', max_length=100, blank=True, null=True, verbose_name='封面图') address = models.CharField(max_length=150, verbose_name='机构地址') city = models.ForeignKey(CityDict, on_delete=models.CASCADE, verbose_name='所在城市') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') class Meta: verbose_name_plural = verbose_name = '课程机构' def get_teacher_nums(self): return self.teachers.count() def change_fav_nums(self, add=1): self.fav_nums += add self.save(update_fields=['fav_nums']) def __str__(self): return self.name ``` 然后再模板中使用`<p>讲 师 数:{{ course.course_org.get_teacher_nums }}</p>`来获取数量 方法二:直接在模板中获取 ```html <p>讲 师 数:{{ course.course_org.teachers.count }}</p> ``` ### 课程所在机构的课程数量 ```html <p>课 程 数:{{ course.course_org.courses.count }}</p> ``` ### 课程和机构收藏功能 ```html <ul class="cmp-list"> {# <li><a href="#."><i class="fa fa-heart"></i> 添加收藏</a></li>#} {# 收藏与取消收藏课程#} <i class="fa fa-heart" style="color: #FF8040"></i> {% if has_fav_course %} <a href="javascript:void(0)" id="add_fav_course_button" style="color: #FFA042"> 取消收藏</a> {% else %} <a href="javascript:void(0)" id="add_fav_course_button" style="color: #02DF82"> 添加收藏</a> {% endif %} </ul> <p> {# 机构收藏与取消机构收藏 #} {% if has_fav_org %} <button id="add_fav_org_button" class="btn-round btn-light" style="background: #FFA042">取消收藏</button> {% else %} <button id="add_fav_org_button" class="btn-round btn-light" style="background: #02DF82">添加收藏</button> {% endif %} </p> <script type="text/javascript"> //添加或取消收藏 function add_fav(current_elem, fav_id, fav_type){ $.ajax({ cache: false, type: "POST", url:"{% url 'org:add_fav' %}", data:{'fav_id':fav_id, 'fav_type':fav_type}, async: true, beforeSend:function(xhr, settings){ xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}"); }, success: function(data) { if(data.fav_status === 'fail'){ if(data.fav_msg === '用户未登录'){ window.location.href="/login/?next={{ request.path }}"; }else{ alert(data.fav_msg) } }else if(data.fav_status === 'success'){ current_elem.text(data.fav_msg); // 修改按钮的颜色 if (data.fav_msg === '取消收藏') { if (fav_type === 2) { document.getElementById('add_fav_org_button').style.background = '#FFA042'; } else if (fav_type === 1) { document.getElementById('add_fav_course_button').style.color = '#FFA042'; } } else if (data.fav_msg === '添加收藏') { if (fav_type === 2) { document.getElementById('add_fav_org_button').style.background = '#02DF82'; } else if (fav_type === 1) { document.getElementById('add_fav_course_button').style.color = '#02DF82'; } } } }, }); } // 收藏机构点击 $('#add_fav_org_button').on('click', function(){ add_fav($(this), {{ course.course_org.id }}, 2); }); // 收藏课程点击 $('#add_fav_course_button').on('click', function(){ add_fav($(this), {{ course.id }}, 1); }); </script> ``` ### 相关相似课程推荐Tag 创建一个标签(Tag)模型 ```python # 课程类别 class Tag(models.Model): name = models.CharField(max_length=50, verbose_name='课程标签') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') class Meta: verbose_name = verbose_name_plural = '课程标签' def __str__(self): return self.name # 课程信息表 class Course(models.Model): DEGREE_CHOICES = ( ("cj", "初级"), ("zj", "中级"), ("gj", "高级") ) name = models.CharField(max_length=50, verbose_name='课程名') desc = models.CharField(max_length=300, verbose_name='课程描述') # 后面会改为富文本 detail = models.TextField(verbose_name='课程详情') degree = models.CharField(max_length=3, choices=DEGREE_CHOICES, verbose_name='课程难度') learn_times = models.IntegerField(default=0, verbose_name='学习时长(分钟数)') # 点击开始学习后记录学习人数 students = models.IntegerField(default=0, verbose_name='学习人数') fav_nums = models.IntegerField(default=0, verbose_name='收藏人数') image = models.ImageField(upload_to='course/%Y/%m', max_length=100, blank=True, null=True, verbose_name='封面图(160*160px)') # 点击到课程信息界面即需要记录点击数 click_nums = models.IntegerField(default=0, verbose_name='点击数') add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间') course_org = models.ForeignKey(CourseOrg, null=True, blank=True, related_name='courses', on_delete=models.CASCADE, verbose_name='所属机构') category = models.ForeignKey(Category, null=True, blank=True, on_delete=models.SET_NULL, related_name='courses', verbose_name='课程类别') # 课程类别删除后课程该字段设置为null tags = models.ManyToManyField(Tag, related_name='courses', blank=True, verbose_name='课程标签') class Meta: verbose_name = verbose_name_plural = '课程' def get_lesson_nums(self): # 获取课程章节数,如果章节模型中未定义关联名称(related_name)则直接使用字段名_set来获取 return self.lesson_set.all().count() def __str__(self): return self.name ``` 同步数据库 ```python manage.py@DjangoOnlineLearningPlatform > makemigrations courses manage.py@DjangoOnlineLearningPlatform > migrate courses ``` adminx.py注册 ```python class TagAdmin(object): list_display = ['name', 'add_time'] xadmin.site.register(Tag, TagAdmin) ``` 然后还需要在users/adminx.py中添加到`GlobalSettings(object)`配置中 **获取相似的课程similar_course** ```python from django.db.models.aggregates import Count # 单个课程详情 class CourseDetailView(View): def get(self, request, course_id): course = Course.objects.get(id=course_id) # 增加课程点击数 course.click_nums += 1 course.save(update_fields=['click_nums']) # 相关推荐 course_tags_ids = course.tags.values_list('id', flat=True) # 获取当前课程所有标签的id similar_course = Course.objects.filter(tags__in=course_tags_ids).exclude(id=course.id) # 获取包含这些标签的课程并排除当前课程 similar_course = similar_course.annotate(same_tags=Count('tags')).order_by('-same_tags', '-students')[:3] # 使用Count聚合函数来生成一个计算字段same_tags # 课程和机构是否已收藏 has_fav_course = False has_fav_org = False # 必须是用户已登录我们才需要判断。 if request.user.is_authenticated: if UserFavorite.objects.filter(user=request.user, fav_id=course.id, fav_type=1): # 该课程已收藏 has_fav_course = True if UserFavorite.objects.filter(user=request.user, fav_id=course.course_org.id, fav_type=2): # 该机构已收藏 has_fav_org = True # 标记当前页,用于页面选中active current_access_url = 'course' return render(request, 'course-detail.html', locals()) ``` ### 该课程学习用户显示 利用`UserCourse`表进行查询 ```python # 单个课程详情 class CourseDetailView(View): def get(self, request, course_id): course = Course.objects.get(id=course_id) # 增加课程点击数 course.click_nums += 1 course.save(update_fields=['click_nums']) # 相关推荐 course_tags_ids = course.tags.values_list('id', flat=True) # 获取当前课程所有标签的id similar_course = Course.objects.filter(tags__in=course_tags_ids).exclude(id=course.id) # 获取包含这些标签的课程并排除当前课程 similar_course = similar_course.annotate(same_tags=Count('tags')).order_by('-same_tags', '-students')[:3] # 使用Count聚合函数来生成一个计算字段same_tags # 学习该课程的用户 user_courses = UserCourse.objects.filter(course=course) print(user_courses) user_courses = user_courses print(user_courses) # 课程和机构是否已收藏 has_fav_course = False has_fav_org = False # 必须是用户已登录我们才需要判断。 if request.user.is_authenticated: if UserFavorite.objects.filter(user=request.user, fav_id=course.id, fav_type=1): # 该课程已收藏 has_fav_course = True if UserFavorite.objects.filter(user=request.user, fav_id=course.course_org.id, fav_type=2): # 该机构已收藏 has_fav_org = True # 标记当前页,用于页面选中active current_access_url = 'course' return render(request, 'course-detail.html', locals()) ``` 模板中显示 ```html <div class="row"> <div class="col-xs-2">学习<br>用户</div> {% for user_course in user_courses %} <div class="col-xs-2"> <a href="javascript:void(0)" title="{{ user_courses.user.nick_name }}({{ user_course.user.username }})"> <img class="img-responsive" style="height: auto; max-width: 60px;" src="{{ user_course.user.image.url }}" alt=""> </a> </div> {% endfor %} </div> ``` 假如该对应关系中有重复数据呢?应该怎么去重,使用`distinct()`函数 ```python # 学习该课程的用户,首先获取该课程在UserCourse对应关系,然后查询UserCourse表中的所有用户,使用distinct()去重 user_courses = UserCourse.objects.filter(course=course) # print(user_courses) user_courses = user_courses.values('user__nick_name', 'user__username', 'user__image').distinct() # print(user_courses) ``` 模板中使用,这儿需要用到media路径 修改settings.py ```python TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates'), ], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'django.template.context_processors.media', # 前端使用{{ MEDIA_URL }} ], }, }, ] ``` 然后直接使用字典列表中的值 ```html <div class="row"> <div class="col-xs-2">学习<br>用户</div> {% for user_course in user_courses %} <div class="col-xs-2"> <a href="javascript:void(0)" title="{{ user_courses.user__nick_name }}({{ user_course.user__username }})"> <img class="img-responsive" style="height: auto; max-width: 60px;" src="{{ MEDIA_URL }}{{ user_course.user__image }}" alt=""> </a> </div> {% endfor %} </div> </div> ```
很赞哦! (0)
相关文章
文章交流
- emoji
当前用户
未登录,点击 登录专题目录
- 【Django在线教育平台】01.创建Django虚拟环境和项目
- 【Django在线教育平台】02.创建该项目用到的数据库模型类
- 【Django在线教育平台】03.xadmin后台系统配置,将models注册到xadmin中
- 【Django在线教育平台】04.模板配置,完成用户登录相关页面和逻辑
- 【Django在线教育平台】05.用户注册功能实现
- 【Django在线教育平台】06.找回密码,实现忘记密码及重置密码功能
- 【Django在线教育平台】07.授课机构列表显示,分页、分类筛选、排序功能
- 【Django在线教育平台】08.学习咨询表单ajax提交
- 【Django在线教育平台】09.机构详情、机构课程详情页
- 【Django在线教育平台】10.机构讲师、机构介绍详情页
- 【Django在线教育平台】11.机构收藏功能实现
- 【Django在线教育平台】12.课程列表及详情展示
- 【Django在线教育平台】13.课程内容页,该课程评论功能
- 【Django在线教育平台】14.用户登陆后开始学习,播放课程视频
- 【Django在线教育平台】15.授课讲师列表和详情功能
- 【Django在线教育平台】16.导航选中状态,全局搜索功能实现
- 【Django在线教育平台】17.个人中心用户修改密码、头像
- 【Django在线教育平台】18.个人中心修改邮箱及其他信息
- 【Django在线教育平台】19.个人中心显示我的课程、收藏、消息页面
- 【Django在线教育平台】20.用户退出功能
- 【Django在线教育平台】21.其他功能完善
- 【Django在线教育平台】22.xadmin的其它常见功能