luffcc项目-07-前端显示课程列表页面、后端实现课程分类列表接口、后端实现课程信息列表接口、按照指定分类显示课程信息、加分页

课程列表页

一、前端显示课程列表页面

Course.vue

<template>
  <div class="course">
    <Vheader></Vheader>
    <div class="main">
      <!-- 筛选条件 -->
      <div class="condition">
        <ul class="cate-list">
          <li class="title">课程分类:</li>
          <li class="this">全部</li>
          <li>Python</li>
          <li>Linux运维</li>
          <li>Python进阶</li>
          <li>开发工具</li>
          <li>Go语言</li>
          <li>机器学习</li>
          <li>技术生涯</li>
        </ul>



      </div>
      <!-- 课程列表 -->
      <div class="course-list">
        <div class="course-item">
          <div class="course-image">
            <img src="/static/img/course-cover.jpeg" alt="">
          </div>
          <div class="course-info">
            <h3><router-link to="/course/detail/1">Python开发21天入门</router-link> <span><img src="/static/img/avatar1.svg" alt="">100人已加入学习</span></h3>
            <p class="teather-info">Alex 金角大王 老男孩Python教学总监 <span>共154课时/更新完成</span></p>
            <ul class="lesson-list">
              <li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码初识编码初识编码初识编码</span> <span class="free">免费</span></li>
            </ul>
            <div class="pay-box">
              <span class="discount-type">限时免费</span>
              <span class="discount-price">¥0.00元</span>
              <span class="original-price">原价:9.00元</span>
              <span class="buy-now">立即购买</span>
            </div>
          </div>
        </div>
        <div class="course-item">
          <div class="course-image">
            <img src="/static/img/course-cover.jpeg" alt="">
          </div>
          <div class="course-info">
            <h3>Python开发21天入门 <span><img src="/static/img/avatar1.svg" alt="">100人已加入学习</span></h3>
            <p class="teather-info">Alex 金角大王 老男孩Python教学总监 <span>共154课时/更新完成</span></p>
            <ul class="lesson-list">
              <li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码初识编码初识编码初识编码</span> <span class="free">免费</span></li>
            </ul>
            <div class="pay-box">
              <span class="discount-type">限时免费</span>
              <span class="discount-price">¥0.00元</span>
              <span class="original-price">原价:9.00元</span>
              <span class="buy-now">立即购买</span>
            </div>
          </div>
        </div>
        <div class="course-item">
          <div class="course-image">
            <img src="/static/img/course-cover.jpeg" alt="">
          </div>
          <div class="course-info">
            <h3>Python开发21天入门 <span><img src="/static/img/avatar1.svg" alt="">100人已加入学习</span></h3>
            <p class="teather-info">Alex 金角大王 老男孩Python教学总监 <span>共154课时/更新完成</span></p>
            <ul class="lesson-list">
              <li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码初识编码初识编码初识编码</span> <span class="free">免费</span></li>
            </ul>
            <div class="pay-box">
              <span class="discount-type">限时免费</span>
              <span class="discount-price">¥0.00元</span>
              <span class="original-price">原价:9.00元</span>
              <span class="buy-now">立即购买</span>
            </div>
          </div>
        </div>
        <div class="course-item">
          <div class="course-image">
            <img src="/static/img/course-cover.jpeg" alt="">
          </div>
          <div class="course-info">
            <h3>Python开发21天入门 <span><img src="/static/img/avatar1.svg" alt="">100人已加入学习</span></h3>
            <p class="teather-info">Alex 金角大王 老男孩Python教学总监 <span>共154课时/更新完成</span></p>
            <ul class="lesson-list">
              <li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码初识编码初识编码初识编码</span> <span class="free">免费</span></li>
            </ul>
            <div class="pay-box">
              <span class="discount-type">限时免费</span>
              <span class="discount-price">¥0.00元</span>
              <span class="original-price">原价:9.00元</span>
              <span class="buy-now">立即购买</span>
            </div>
          </div>
        </div>
      </div>
    </div>
    <Footer></Footer>
  </div>
</template>

<script>
  import Vheader from "./common/Vheader"
  import Footer from "./common/Footer"
  export default {
      name: "Course",
      data(){
        return{
          category:0,
        }
      },
      components:{
        Vheader,
        Footer,
      }
  }
</script>



<style scoped>
  .course{
    background: #f6f6f6;
  }
  .course .main{
    width: 1100px;
    margin: 35px auto 0;
  }
  .course .condition{
    margin-bottom: 35px;
    padding: 25px 30px 25px 20px;
    background: #fff;
    border-radius: 4px;
    box-shadow: 0 2px 4px 0 #f0f0f0;
  }
  .course .cate-list{
    border-bottom: 1px solid #333;
    border-bottom-color: rgba(51,51,51,.05);
    padding-bottom: 18px;
    margin-bottom: 17px;
  }
  .course .cate-list::after{
    content:"";
    display: block;
    clear: both;
  }
  .course .cate-list li{
    float: left;
    font-size: 16px;
    padding: 6px 15px;
    line-height: 16px;
    margin-left: 14px;
    position: relative;
    transition: all .3s ease;
    cursor: pointer;
    color: #4a4a4a;
    border: 1px solid transparent; /* transparent 透明 */
  }
  .course .cate-list .title{
    color: #888;
    margin-left: 0;
    letter-spacing: .36px;
    padding: 0;
    line-height: 28px;
  }
  .course .cate-list .this{
    color: #ffc210;
    border: 1px solid #ffc210!important;
    border-radius: 30px;
  }
  .course .ordering::after{
    content:"";
    display: block;
    clear: both;
  }
  .course .ordering ul{
    float: left;
  }
  .course .ordering ul::after{
    content:"";
    display: block;
    clear: both;
  }
  .course .ordering .condition-result{
    float: right;
    font-size: 14px;
    color: #9b9b9b;
    line-height: 28px;
  }
  .course .ordering ul li{
    float: left;
    padding: 6px 15px;
    line-height: 16px;
    margin-left: 14px;
    position: relative;
    transition: all .3s ease;
    cursor: pointer;
    color: #4a4a4a;
  }
  .course .ordering .title{
    font-size: 16px;
    color: #888;
    letter-spacing: .36px;
    margin-left: 0;
    padding:0;
    line-height: 28px;
  }
  .course .ordering .this{
    color: #ffc210;
  }
  .course .ordering .price{
    position: relative;
  }
  .course .ordering .price::before,
  .course .ordering .price::after{
    cursor: pointer;
    content:"";
    display: block;
    width: 0px;
    height: 0px;
    border: 5px solid transparent;
    position: absolute;
    right: 0;
  }
  .course .ordering .price::before{
    border-bottom: 5px solid #aaa;
    margin-bottom: 2px;
    top: 2px;
  }
  .course .ordering .price::after{
    border-top: 5px solid #aaa;
    bottom: 2px;
  }
  .course .course-item:hover{
    box-shadow: 4px 6px 16px rgba(0,0,0,.5);
  }
  .course .course-item{
    width: 1050px;
    background: #fff;
    padding: 20px 30px 20px 20px;
    margin-bottom: 35px;
    border-radius: 2px;
    cursor: pointer;
    box-shadow: 2px 3px 16px rgba(0,0,0,.1);
    /* css3.0 过渡动画 hover 事件操作 */
    transition: all .2s ease;
  }
  .course .course-item::after{
    content:"";
    display: block;
    clear: both;
  }
  /* 顶级元素 父级元素  当前元素{} */
  .course .course-item .course-image{
    float: left;
    width: 423px;
    height: 210px;
    margin-right: 30px;
  }
  .course .course-item .course-image img{
    width: 100%;
  }
  .course .course-item .course-info{
    float: left;
    width: 596px;
  }
  .course-item .course-info h3 {
    font-size: 26px;
    color: #333;
    font-weight: normal;
    margin-bottom: 8px;
  }
  .course-item .course-info h3 span{
    font-size: 14px;
    color: #9b9b9b;
    float: right;
    margin-top: 14px;
  }
  .course-item .course-info h3 span img{
      width: 11px;
      height: auto;
      margin-right: 7px;
  }
  .course-item .course-info .teather-info{
      font-size: 14px;
      color: #9b9b9b;
      margin-bottom: 14px;
      padding-bottom: 14px;
      border-bottom: 1px solid #333;
      border-bottom-color: rgba(51,51,51,.05);
  }
  .course-item .course-info .teather-info span{
      float: right;
  }
  .course-item .lesson-list::after{
      content:"";
      display: block;
      clear: both;
  }
  .course-item .lesson-list li {
    float: left;
    width: 44%;
    font-size: 14px;
    color: #666;
    padding-left: 22px;
    /* background: url("路径") 是否平铺 x轴位置 y轴位置 */
    background: url("/static/image/play-icon-gray.svg") no-repeat left 4px;
    margin-bottom: 15px;
  }
  .course-item .lesson-list li .lesson-title{
      /* 以下3句,文本内容过多,会自动隐藏,并显示省略符号 */
      text-overflow: ellipsis;
      overflow: hidden;
      white-space: nowrap;
      display:inline-block;
      max-width: 200px;
  }
  .course-item .lesson-list li:hover{
      background-image: url("/static/image/play-icon-yellow.svg");
      color: #ffc210;
  }
  .course-item .lesson-list li .free{
      width: 34px;
      height: 20px;
      color: #fd7b4d;
      vertical-align: super;
      margin-left: 10px;
      border: 1px solid #fd7b4d;
      border-radius: 2px;
      text-align: center;
      font-size: 13px;
      white-space: nowrap;
  }
  .course-item .lesson-list li:hover .free{
      color: #ffc210;
      border-color: #ffc210;
  }
  .course-item .pay-box::after{
    content:"";
    display: block;
    clear: both;
  }
  .course-item .pay-box .discount-type{
    padding: 6px 10px;
    font-size: 16px;
    color: #fff;
    text-align: center;
    margin-right: 8px;
    background: #fa6240;
    border: 1px solid #fa6240;
    border-radius: 10px 0 10px 0;
    float: left;
  }
  .course-item .pay-box .discount-price{
    font-size: 24px;
    color: #fa6240;
    float: left;
  }
  .course-item .pay-box .original-price{
    text-decoration: line-through;
    font-size: 14px;
    color: #9b9b9b;
    margin-left: 10px;
    float: left;
    margin-top: 10px;
  }
  .course-item .pay-box .buy-now{
    width: 120px;
    height: 38px;
    background: transparent;
    color: #fa6240;
    font-size: 16px;
    border: 1px solid #fd7b4d;
    border-radius: 3px;
    transition: all .2s ease-in-out;
    float: right;
    text-align: center;
    line-height: 38px;
  }
  .course-item .pay-box .buy-now:hover{
    color: #fff;
    background: #ffc210;
    border: 1px solid #ffc210;
  }
</style>

index.js

...
import Course from '@/components/Couese'
...
    {
      path: '/course',

      component: Course
    }

二、课程子应用创建

E:\axiangmu\luffcc\lyapi\lyapi\apps>python ../../manage.py startapp course

注册子应用

INSTALLED_APPS = [
		...
    'course',
]

三、数据模型创建

course/models.py

from django.db import models
from lyapi.utils.models import BaseModel


# Create your models here.
class CourseCategory(BaseModel):
    """
    课程分类
    """
    name = models.CharField(max_length=64, unique=True, verbose_name="分类名称")

    class Meta:
        db_table = "ly_course_category"
        verbose_name = "课程分类"
        verbose_name_plural = "课程分类"

    def __str__(self):
        return "%s" % self.name


class Course(BaseModel):
    """
    专题课程
    """
    course_type = (
        (0, '付费'),
        (1, 'VIP专享'),
        (2, '学位课程')
    )
    level_choices = (
        (0, '初级'),
        (1, '中级'),
        (2, '高级'),
    )
    status_choices = (
        (0, '上线'),
        (1, '下线'),
        (2, '预上线'),
    )
    name = models.CharField(max_length=128, verbose_name="课程名称")
    course_img = models.ImageField(upload_to="course", max_length=255, verbose_name="封面图片", blank=True, null=True)

    # 费用类型字段是为了后期一些其他功能拓展用的,现在可以先不用,或者去掉它,目前我们项目用不到
    course_type = models.SmallIntegerField(choices=course_type, default=0, verbose_name="付费类型")
    # 这个字段是课程详情页里面展示的,并且详情介绍里面用户将来可能要上传一些图片之类的,所以我们会潜入富文本编辑器,让用户填写数据的时候可以上传图片啊、写标题啊、css、html等等内容
    brief = models.TextField(max_length=2048, verbose_name="详情介绍", null=True, blank=True)

    level = models.SmallIntegerField(choices=level_choices, default=1, verbose_name="难度等级")
    pub_date = models.DateField(verbose_name="发布日期", auto_now_add=True)
    period = models.IntegerField(verbose_name="建议学习周期(day)", default=7)

    # 课件资料的存放路径
    attachment_path = models.FileField(max_length=128, verbose_name="课件路径", blank=True, null=True)
    status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="课程状态")
    course_category = models.ForeignKey("CourseCategory", on_delete=models.CASCADE, null=True, blank=True,
                                        verbose_name="课程分类")
    students = models.IntegerField(verbose_name="学习人数", default=0)
    lessons = models.IntegerField(verbose_name="总课时数量", default=0)

    # 总课时数量可能10个,但是目前之更新了3个,就跟小说、电视剧连载似的。
    pub_lessons = models.IntegerField(verbose_name="课时更新数量", default=0)

    # 课程原价
    price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="课程原价", default=0)
    teacher = models.ForeignKey("Teacher", on_delete=models.DO_NOTHING, null=True, blank=True, verbose_name="授课老师")

    class Meta:
        db_table = "ly_course"
        verbose_name = "专题课程"
        verbose_name_plural = "专题课程"

    def __str__(self):
        return "%s" % self.name


class Teacher(BaseModel):
    """讲师、导师表"""
    role_choices = (
        (0, '讲师'),
        (1, '导师'),
        (2, '班主任'),
    )
    name = models.CharField(max_length=32, verbose_name="讲师title")
    role = models.SmallIntegerField(choices=role_choices, default=0, verbose_name="讲师身份")
    title = models.CharField(max_length=64, verbose_name="职位、职称")
    signature = models.CharField(max_length=255, verbose_name="导师签名", help_text="导师签名", blank=True, null=True)
    image = models.ImageField(upload_to="teacher", null=True, verbose_name="讲师封面")
    brief = models.TextField(max_length=1024, verbose_name="讲师描述")

    class Meta:
        db_table = "ly_teacher"
        verbose_name = "讲师导师"
        verbose_name_plural = "讲师导师"

    def __str__(self):
        return "%s" % self.name


class CourseChapter(BaseModel):
    """课程章节"""
    course = models.ForeignKey("Course", related_name='coursechapters', on_delete=models.CASCADE, verbose_name="课程名称")
    chapter = models.SmallIntegerField(verbose_name="第几章", default=1)
    name = models.CharField(max_length=128, verbose_name="章节标题")
    summary = models.TextField(verbose_name="章节介绍", blank=True, null=True)
    pub_date = models.DateField(verbose_name="发布日期", auto_now_add=True)

    class Meta:
        db_table = "ly_course_chapter"
        verbose_name = "课程章节"
        verbose_name_plural = "课程章节"

    def __str__(self):
        return "%s:(第%s章)%s" % (self.course, self.chapter, self.name)


class CourseLesson(BaseModel):
    """课程课时"""
    section_type_choices = (
        (0, '文档'),
        (1, '练习'),
        (2, '视频')
    )
    chapter = models.ForeignKey("CourseChapter", related_name='coursesections', on_delete=models.CASCADE,
                                verbose_name="课程章节")
    name = models.CharField(max_length=128, verbose_name="课时标题")
    # orders = models.PositiveSmallIntegerField(verbose_name="课时排序") #在basemodel里面已经有了排序了
    section_type = models.SmallIntegerField(default=2, choices=section_type_choices, verbose_name="课时种类")
    section_link = models.CharField(max_length=255, blank=True, null=True, verbose_name="课时链接",
                                    help_text="若是video,填vid,若是文档,填link")
    duration = models.CharField(verbose_name="视频时长", blank=True, null=True,
                                max_length=32)  # 仅在前端展示使用,所以直接让上传视频的用户直接填写时长进来就可以了。
    pub_date = models.DateTimeField(verbose_name="发布时间", auto_now_add=True)
    free_trail = models.BooleanField(verbose_name="是否可试看", default=False)
    course = models.ForeignKey('Course', related_name='course_lesson', verbose_name='课程', on_delete=models.CASCADE,
                               null=True, blank=True)
    is_show_list = models.BooleanField(verbose_name='是否推荐到课程列表', default=False)
    lesson = models.IntegerField(verbose_name="第几课时")


class Meta:
    db_table = "ly_course_lesson"
    verbose_name = "课程课时"
    verbose_name_plural = "课程课时"


def __str__(self):
    return "%s-%s" % (self.chapter, self.name)

执行数据迁移

python manage.py makemigrations
python manage.py migrate

把当前新增的课程模型注册到xadmin里面.
courser/adminx.py,代码:

import xadmin

from .models import CourseCategory
class CourseCategoryModelAdmin(object):
    """课程分类模型管理类"""
    pass
xadmin.site.register(CourseCategory, CourseCategoryModelAdmin)


from .models import Course
class CourseModelAdmin(object):
    """课程模型管理类"""
    pass
xadmin.site.register(Course, CourseModelAdmin)


from .models import Teacher
class TeacherModelAdmin(object):
    """老师模型管理类"""
    pass
xadmin.site.register(Teacher, TeacherModelAdmin)


from .models import CourseChapter
class CourseChapterModelAdmin(object):
    """课程章节模型管理类"""
    pass
xadmin.site.register(CourseChapter, CourseChapterModelAdmin)



from .models import CourseLesson
class CourseLessonModelAdmin(object):
    """课程课时模型管理类"""
    pass
xadmin.site.register(CourseLesson, CourseLessonModelAdmin)

然后在xadmin客户端添加数据

也可以使用SQL语句

INSERT INTO `ly_course_category` (`id`,`orders`,`is_show`,`is_deleted`,`created_time`,`updated_time`,`name`)
 VALUES
(1,11,1,0,'2019-08-13 07:08:47.100074','2019-08-13 07:44:05.903782','python'),
(2,0,1,0,'2019-08-13 07:08:51.451093','2019-08-13 07:43:54.558940','go编程'),
(3,3,1,0,'2019-08-13 07:08:57.390196','2019-08-13 07:08:57.390226','Linux运维'),
(4,4,1,0,'2019-08-13 07:09:11.465963','2019-08-13 07:09:11.465994','前端开发'),
(5,11,1,0,'2019-08-13 07:08:47.100074','2019-08-13 07:44:05.903782','php编程'),
(6,0,1,0,'2019-08-13 07:08:51.451093','2019-08-13 07:43:54.558940','C/C++'),
(7,3,1,0,'2019-08-13 07:08:57.390196','2019-08-13 07:08:57.390226','java web'),
(8,4,1,0,'2019-08-13 07:09:11.465963','2019-08-13 07:09:11.465994','UI设计'),
(9,11,1,0,'2019-08-13 07:09:11.465963','2019-08-13 07:09:11.465994','语文'),
(10,145,2,0,'2019-08-13 07:09:11.465963','2019-08-13 07:09:11.465994','数学'),
(11,1,2,0,'2019-08-13 07:09:11.465963','2019-08-13 07:09:11.465994','英语');

四、后端实现课程分类列表接口

1.创建序列化器

course/serializers.py

from rest_framework import serializers
from . import models
class CourseCategoryModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = models.CourseCategory
        fields = ['id', 'name']
2.创建视图

course/views.py

from . import models
# Create your views here.
from rest_framework.generics import ListAPIView
from .serializers import CourseCategoryModelSerializer, CourseModelsSerializer


class CategoryView(ListAPIView):

    queryset = models.CourseCategory.objects.filter(is_deleted=False,is_show=True)
    serializer_class = CourseCategoryModelSerializer
3.注册路由
course/urls.py  文件

    from django.urls import path
    from . import views

    urlpatterns = [
        path(r'categorys/', views.CategoryView.as_view(),),
    ]

# 总路由
    path('course/', include("course.urls")),
4.客户端发送请求获取课程分类信息和高亮效果切换

Course.vue

<template>
  <div class="course">
    <Vheader></Vheader>
    <div class="main">
      <!-- 筛选条件 -->
      <div class="condition">
        <ul class="cate-list">
          <li class="title">课程分类:</li>
          <li :class="{this:category===0}" @click="category=0">全部</li>
          <li v-for="(value, index) in category_list" :key="value.id" @click="category=value.id" :class="{this:category===value.id}">{{value.name}}</li>

        </ul>


      </div>
      <!-- 课程列表 -->
      <div class="course-list">
        <div class="course-item">
          <div class="course-image">
            <img src="/static/img/course-cover.jpeg" alt="">
          </div>
          <div class="course-info">
            <h3><router-link to="/course/detail/1">Python开发21天入门</router-link> <span><img src="/static/img/avatar1.svg" alt="">100人已加入学习</span></h3>
            <p class="teather-info">Alex 金角大王 老男孩Python教学总监 <span>共154课时/更新完成</span></p>
            <ul class="lesson-list">
              <li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码初识编码初识编码初识编码</span> <span class="free">免费</span></li>
            </ul>
            <div class="pay-box">
              <span class="discount-type">限时免费</span>
              <span class="discount-price">¥0.00元</span>
              <span class="original-price">原价:9.00元</span>
              <span class="buy-now">立即购买</span>
            </div>
          </div>
        </div>
        <div class="course-item">
          <div class="course-image">
            <img src="/static/img/course-cover.jpeg" alt="">
          </div>
          <div class="course-info">
            <h3>Python开发21天入门 <span><img src="/static/img/avatar1.svg" alt="">100人已加入学习</span></h3>
            <p class="teather-info">Alex 金角大王 老男孩Python教学总监 <span>共154课时/更新完成</span></p>
            <ul class="lesson-list">
              <li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码初识编码初识编码初识编码</span> <span class="free">免费</span></li>
            </ul>
            <div class="pay-box">
              <span class="discount-type">限时免费</span>
              <span class="discount-price">¥0.00元</span>
              <span class="original-price">原价:9.00元</span>
              <span class="buy-now">立即购买</span>
            </div>
          </div>
        </div>
        <div class="course-item">
          <div class="course-image">
            <img src="/static/img/course-cover.jpeg" alt="">
          </div>
          <div class="course-info">
            <h3>Python开发21天入门 <span><img src="/static/img/avatar1.svg" alt="">100人已加入学习</span></h3>
            <p class="teather-info">Alex 金角大王 老男孩Python教学总监 <span>共154课时/更新完成</span></p>
            <ul class="lesson-list">
              <li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码初识编码初识编码初识编码</span> <span class="free">免费</span></li>
            </ul>
            <div class="pay-box">
              <span class="discount-type">限时免费</span>
              <span class="discount-price">¥0.00元</span>
              <span class="original-price">原价:9.00元</span>
              <span class="buy-now">立即购买</span>
            </div>
          </div>
        </div>
        <div class="course-item">
          <div class="course-image">
            <img src="/static/img/course-cover.jpeg" alt="">
          </div>
          <div class="course-info">
            <h3>Python开发21天入门 <span><img src="/static/img/avatar1.svg" alt="">100人已加入学习</span></h3>
            <p class="teather-info">Alex 金角大王 老男孩Python教学总监 <span>共154课时/更新完成</span></p>
            <ul class="lesson-list">
              <li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码</span> <span class="free">免费</span></li>
              <li><span class="lesson-title">01 | 第1节:初识编码初识编码初识编码初识编码</span> <span class="free">免费</span></li>
            </ul>
            <div class="pay-box">
              <span class="discount-type">限时免费</span>
              <span class="discount-price">¥0.00元</span>
              <span class="original-price">原价:9.00元</span>
              <span class="buy-now">立即购买</span>
            </div>
          </div>
        </div>
      </div>
    </div>
    <Footer></Footer>
  </div>
</template>

<script>
  import Vheader from "./common/Vheader"
  import Footer from "./common/Footer"
  export default {
      name: "Course",
      data(){
        return{
          category:0,  //默认分类zhi
          category_list:[],
        }
      },
      components:{
        Vheader,
        Footer,
      },

      created() {
        this.$axios.get(`${this.$settings.Host}/course/categorys/`)
        .then((res)=>{
          console.log(res.data);
          this.category_list = res.data;
        })
      }


  }
</script>



<style scoped>
  .course{
    background: #f6f6f6;
  }
  .course .main{
    width: 1100px;
    margin: 35px auto 0;
  }
  .course .condition{
    margin-bottom: 35px;
    padding: 25px 30px 25px 20px;
    background: #fff;
    border-radius: 4px;
    box-shadow: 0 2px 4px 0 #f0f0f0;
  }
  .course .cate-list{
    border-bottom: 1px solid #333;
    border-bottom-color: rgba(51,51,51,.05);
    padding-bottom: 18px;
    margin-bottom: 17px;
  }
  .course .cate-list::after{
    content:"";
    display: block;
    clear: both;
  }
  .course .cate-list li{
    float: left;
    font-size: 16px;
    padding: 6px 15px;
    line-height: 16px;
    margin-left: 14px;
    position: relative;
    transition: all .3s ease;
    cursor: pointer;
    color: #4a4a4a;
    border: 1px solid transparent; /* transparent 透明 */
  }
  .course .cate-list .title{
    color: #888;
    margin-left: 0;
    letter-spacing: .36px;
    padding: 0;
    line-height: 28px;
  }
  .course .cate-list .this{
    color: #ffc210;
    border: 1px solid #ffc210!important;
    border-radius: 30px;
  }
  .course .ordering::after{
    content:"";
    display: block;
    clear: both;
  }
  .course .ordering ul{
    float: left;
  }
  .course .ordering ul::after{
    content:"";
    display: block;
    clear: both;
  }
  .course .ordering .condition-result{
    float: right;
    font-size: 14px;
    color: #9b9b9b;
    line-height: 28px;
  }
  .course .ordering ul li{
    float: left;
    padding: 6px 15px;
    line-height: 16px;
    margin-left: 14px;
    position: relative;
    transition: all .3s ease;
    cursor: pointer;
    color: #4a4a4a;
  }
  .course .ordering .title{
    font-size: 16px;
    color: #888;
    letter-spacing: .36px;
    margin-left: 0;
    padding:0;
    line-height: 28px;
  }
  .course .ordering .this{
    color: #ffc210;
  }
  .course .ordering .price{
    position: relative;
  }
  .course .ordering .price::before,
  .course .ordering .price::after{
    cursor: pointer;
    content:"";
    display: block;
    width: 0px;
    height: 0px;
    border: 5px solid transparent;
    position: absolute;
    right: 0;
  }
  .course .ordering .price::before{
    border-bottom: 5px solid #aaa;
    margin-bottom: 2px;
    top: 2px;
  }
  .course .ordering .price::after{
    border-top: 5px solid #aaa;
    bottom: 2px;
  }
  .course .course-item:hover{
    box-shadow: 4px 6px 16px rgba(0,0,0,.5);
  }
  .course .course-item{
    width: 1050px;
    background: #fff;
    padding: 20px 30px 20px 20px;
    margin-bottom: 35px;
    border-radius: 2px;
    cursor: pointer;
    box-shadow: 2px 3px 16px rgba(0,0,0,.1);
    /* css3.0 过渡动画 hover 事件操作 */
    transition: all .2s ease;
  }
  .course .course-item::after{
    content:"";
    display: block;
    clear: both;
  }
  /* 顶级元素 父级元素  当前元素{} */
  .course .course-item .course-image{
    float: left;
    width: 423px;
    height: 210px;
    margin-right: 30px;
  }
  .course .course-item .course-image img{
    width: 100%;
  }
  .course .course-item .course-info{
    float: left;
    width: 596px;
  }
  .course-item .course-info h3 {
    font-size: 26px;
    color: #333;
    font-weight: normal;
    margin-bottom: 8px;
  }
  .course-item .course-info h3 span{
    font-size: 14px;
    color: #9b9b9b;
    float: right;
    margin-top: 14px;
  }
  .course-item .course-info h3 span img{
      width: 11px;
      height: auto;
      margin-right: 7px;
  }
  .course-item .course-info .teather-info{
      font-size: 14px;
      color: #9b9b9b;
      margin-bottom: 14px;
      padding-bottom: 14px;
      border-bottom: 1px solid #333;
      border-bottom-color: rgba(51,51,51,.05);
  }
  .course-item .course-info .teather-info span{
      float: right;
  }
  .course-item .lesson-list::after{
      content:"";
      display: block;
      clear: both;
  }
  .course-item .lesson-list li {
    float: left;
    width: 44%;
    font-size: 14px;
    color: #666;
    padding-left: 22px;
    /* background: url("路径") 是否平铺 x轴位置 y轴位置 */
    background: url("/static/image/play-icon-gray.svg") no-repeat left 4px;
    margin-bottom: 15px;
  }
  .course-item .lesson-list li .lesson-title{
      /* 以下3句,文本内容过多,会自动隐藏,并显示省略符号 */
      text-overflow: ellipsis;
      overflow: hidden;
      white-space: nowrap;
      display:inline-block;
      max-width: 200px;
  }
  .course-item .lesson-list li:hover{
      background-image: url("/static/image/play-icon-yellow.svg");
      color: #ffc210;
  }
  .course-item .lesson-list li .free{
      width: 34px;
      height: 20px;
      color: #fd7b4d;
      vertical-align: super;
      margin-left: 10px;
      border: 1px solid #fd7b4d;
      border-radius: 2px;
      text-align: center;
      font-size: 13px;
      white-space: nowrap;
  }
  .course-item .lesson-list li:hover .free{
      color: #ffc210;
      border-color: #ffc210;
  }
  .course-item .pay-box::after{
    content:"";
    display: block;
    clear: both;
  }
  .course-item .pay-box .discount-type{
    padding: 6px 10px;
    font-size: 16px;
    color: #fff;
    text-align: center;
    margin-right: 8px;
    background: #fa6240;
    border: 1px solid #fa6240;
    border-radius: 10px 0 10px 0;
    float: left;
  }
  .course-item .pay-box .discount-price{
    font-size: 24px;
    color: #fa6240;
    float: left;
  }
  .course-item .pay-box .original-price{
    text-decoration: line-through;
    font-size: 14px;
    color: #9b9b9b;
    margin-left: 10px;
    float: left;
    margin-top: 10px;
  }
  .course-item .pay-box .buy-now{
    width: 120px;
    height: 38px;
    background: transparent;
    color: #fa6240;
    font-size: 16px;
    border: 1px solid #fd7b4d;
    border-radius: 3px;
    transition: all .2s ease-in-out;
    float: right;
    text-align: center;
    line-height: 38px;
  }
  .course-item .pay-box .buy-now:hover{
    color: #fff;
    background: #ffc210;
    border: 1px solid #ffc210;
  }
</style>

五、后端实现课程信息列表接口

在xadmin后端添加测试数据

INSERT INTO `ly_teacher` (`id`,`orders`,`is_show`,`is_deleted`,`created_time`,`updated_time`,`name`,`role`,`title`,`signature`,`image`,`brief`)
VALUES 
(1,1,1,0,'2019-08-13 07:13:01.531992','2019-08-13 07:13:01.532043','李老师',0,'xx公司技术总监','洪七公','teacher/logo2x.png','222');


INSERT INTO `ly_course`
(`id`,`orders`,`is_show`,`is_deleted`,`created_time`,`updated_time`,`name`,`course_img`,`course_type`,`brief`,`level`,`pub_date`,`period`,`attachment_path`,`status`,`students`,`lessons`,`pub_lessons`,`price`,`course_category_id`,`teacher_id`)
VALUES
(1,1,1,0,'2019-08-13 07:13:50.678948','2019-08-15 04:07:11.386224','flask框架','course/Loginbg.3377d0c.jpg',0,'<p>xxxx</p>',1,'2019-08-13',7,'README.md',0,99,110,110,1110.00,1,1),
(2,2,1,0,'2019-08-13 07:15:32.490163','2019-08-15 04:13:22.430368','蘑菇街APP','course/course-cover.jpeg',0,'<p>dxxx</p>',2,'2019-08-13',7,'logo.svg',0,10,50,40,666.00,1,1),
(3,3,1,0,'2019-08-13 07:15:32.490163','2019-08-20 10:49:41.880490','django框架','course/2.jpeg',0,'<p>dxxx</p>',1,'2019-08-13',7,'logo.svg',0,10,50,40,330.00,1,1),
(15,4,1,0,'2019-08-13 07:15:32.490163','2019-08-13 07:15:32.490191','python入门','course/2.jpeg',0,'dxxx',2,'2019-08-13',7,'logo.svg',0,10,50,40,411.00,1,1),
(16,5,1,0,'2019-08-13 07:15:32.490163','2019-08-14 02:28:04.791112','hbase入门','course/2.jpeg',0,'dxxx',1,'2019-08-13',7,'logo.svg',0,10,50,40,400.00,7,1),
(17,6,1,0,'2019-08-13 07:15:32.490163','2019-08-13 07:15:32.490191','路飞学城项目实战','course/2.jpeg',0,'dxxx',2,'2019-08-13',7,'logo.svg',0,10,50,40,899.00,1,1),
(18,7,1,0,'2019-08-13 07:15:32.490163','2019-08-14 02:29:47.667133','负载均衡','course/2.jpeg',0,'dxxx',2,'2019-08-13',7,'logo.svg',0,10,50,40,1088.00,6,1),
(19,8,1,0,'2019-08-13 07:15:32.490163','2019-08-13 07:15:32.490191','MVC','course/2.jpeg',0,'dxxx',2,'2019-08-13',7,'logo.svg',0,10,50,40,1500.00,1,1),
(20,9,1,0,'2019-08-13 07:15:32.490163','2019-08-14 02:28:52.126968','21天java入门','course/2.jpeg',0,'dxxx',0,'2019-08-13',7,'logo.svg',0,10,50,40,3000.00,7,1),
(21,10,1,0,'2019-08-13 07:15:32.490163','2019-08-14 02:27:01.850049','7天玩转Linux运维','course/2.jpeg',0,'dxxx',2,'2019-08-13',7,'logo.svg',0,10,50,40,400.00,3,1),
(22,11,1,0,'2019-08-13 07:15:32.490163','2019-08-13 07:15:32.490191','15天掌握flask框架','course/2.jpeg',0,'dxxx',2,'2019-08-13',7,'logo.svg',0,10,50,40,400.00,1,1),
(23,12,1,0,'2019-08-13 07:15:32.490163','2019-08-13 07:23:56.015167','C编程嵌入式','course/2.jpeg',0,'dxxx',1,'2019-08-13',7,'logo.svg',0,10,50,40,399.00,3,1),
(24,13,1,0,'2019-08-13 07:15:32.490163','2019-08-14 02:29:17.872840','3天玩转树莓派','course/2.jpeg',0,'dxxx',2,'2019-08-13',7,'logo.svg',0,10,50,40,400.00,3,1),
(25,14,1,0,'2019-08-13 07:15:32.490163','2019-08-14 02:28:30.783768','MongoDB','course/2.jpeg',0,'dxxx',0,'2019-08-13',7,'logo.svg',0,10,50,40,400.00,3,1),
(26,15,1,0,'2019-08-13 07:15:32.490163','2019-08-14 02:30:09.348192','Beego框架入门','course/2.jpeg',0,'dxxx',1,'2019-08-13',7,'logo.svg',0,10,50,40,699.00,2,1),
(27,16,1,0,'2019-08-13 07:15:32.490163','2019-08-15 02:35:20.997672','beego框架进阶','course/2.jpeg',0,'<p>dxxx</p>',1,'2019-08-13',7,'logo.svg',0,10,50,50,400.00,2,1),
(28,17,1,0,'2019-08-13 07:15:32.490163','2019-08-13 07:23:44.546598','以太坊入门','course/2.jpeg',0,'dxxx',2,'2019-08-13',7,'logo.svg',0,10,50,40,899.00,2,1),
(29,18,1,0,'2019-08-13 07:15:32.490163','2019-08-15 04:05:10.421736','负载均衡','course/2.jpeg',0,'<div style=\"background:#eeeeee; border:1px solid #cccccc; padding:5px 10px\"><span style=\"color:#16a085\"><span style=\"font-family:Arial,Helvetica,sans-serif\"><span style=\"font-size:28px\"><span style=\"background-color:#f39c12\">dxxx</span></span></span></span><img alt=\"\" src=\"/media/2019/08/15/course-cover.jpeg\" /></div>\r\n\r\n<div style=\"background:#eeeeee; border:1px solid #cccccc; padding:5px 10px\">&nbsp;</div>\r\n\r\n<div style=\"background:#eeeeee; border:1px solid #cccccc; padding:5px 10px\">\r\n<table border=\"1\" cellpadding=\"1\" cellspacing=\"1\" style=\"width:500px\">\r\n	<tbody>\r\n		<tr>\r\n			<td>12321</td>\r\n			<td>3232</td>\r\n			<td>111</td>\r\n		</tr>\r\n		<tr>\r\n			<td>33</td>\r\n			<td>33</td>\r\n			<td>22</td>\r\n		</tr>\r\n		<tr>\r\n			<td>11</td>\r\n			<td>22</td>\r\n			<td>23</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p>&nbsp;</p>\r\n</div>',0,'2019-08-13',7,'logo.svg',0,10,50,40,400.00,3,1);

course/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path(r'categorys/', views.CategoryView.as_view(),),
    path(r'courses/', views.CourseView.as_view(),),

]
1.课程列表后台接口视图
class CourseView(ListAPIView):
    queryset = models.Course.objects.filter(is_deleted=False,is_show=True).order_by('id')
    serializer_class = CourseModelsSerializer
2.课程列表页的序列化器
class TeacherModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Teacher
        fields = ['name', 'role','title','signature']


class CourseModelsSerializer(serializers.ModelSerializer):
    # teacher_name = serializers.CharField(source='teacher.name')  #自定义字段,通过sourse关键字就能获取外键关联的指定字段数据,别忘了在fields里面指定一下
    # 方式2
    # 序列化器嵌套
    teacher = TeacherModelSerializer()  #将外键关联的属性指定为关联表的序列化器对象,就能拿到关联表序列化出来的所有数据,还需要在fields中指定一下,注意,名称必须和外键属性名称相同


    class Meta:
        model = models.Course
        # fields = ["id","name","course_img","students","lessons","pub_lessons","price","teacher",'teacher_name']  #teacher外键属性默认拿的是id值
        fields = ["id","name","course_img","students","lessons","pub_lessons","price","teacher","get_lessons"]  #teacher外键属性默认拿的是id值

序列化其中的fields属性中的get_lessons是models.py文件中的Course类中的有一个方法。
通过课程对象获取所有课程列表页中要展示的课时信息

class Course(BaseModel):
    ...

    class Meta:
        db_table = "ly_course"
        verbose_name = "专题课程"
        verbose_name_plural = "专题课程"

    def __str__(self):
        return "%s" % self.name

    # 通过课程对象获取所有课程列表页中要展示的课时信息
    def get_lessons(self):
        chapters = self.coursechapters.all()
        lession_list = []
        for chapter in chapters:
            lessons = chapter.coursesections.filter(is_show_list=True,is_show=True,is_deleted=False)
            for  lesson in lessons:
                lession_list.append({
                    'name':lesson.name,
                    'free_trail':lesson.free_trail,
                    'lesson':lesson.lesson,
                })
        return lession_list[:4]
3.添加章节和课时数据

添加课程章节的测试数据

INSERT INTO `ly_course_chapter` VALUES (1,1,1,0,'2019-08-13 07:24:21.889515','2019-08-13 07:24:21.889542',1,'flask框架快速入门','flask框架快速入门','2019-08-13',1),(2,2,1,0,'2019-08-13 07:24:37.116231','2019-08-15 03:59:17.598352',2,'flask的路由','flask的路由','2019-08-13',1),(3,3,1,0,'2019-08-13 07:24:51.153812','2019-08-15 03:59:22.067057',3,'flask的视图','flask的视图','2019-08-13',1),(4,4,1,0,'2019-08-13 07:25:00.621686','2019-08-15 03:59:29.642805',4,'flask的模型','flask的模型','2019-08-13',1),(5,5,1,0,'2019-08-13 07:24:21.889515','2019-08-13 07:24:21.889542',1,'django框架快速入门','django框架快速入门','2019-08-13',3),(6,6,1,0,'2019-08-13 07:24:37.116231','2019-08-13 07:24:37.116262',2,'django的路由','django的路由','2019-08-13',3),(7,7,1,0,'2019-08-13 07:24:51.153812','2019-08-13 07:24:51.153846',3,'django的视图','django的视图','2019-08-13',3),(8,8,1,0,'2019-08-13 07:25:00.621686','2019-08-13 07:25:00.621768',4,'django的模型','django的模型','2019-08-13',3);

添加课程课时的测试数据

INSERT INTO `ly_course_lesson`
(`id`,`is_show`,`is_deleted`,`created_time`,`updated_time`,`name`,`orders`,`section_type`,`section_link`,`duration`,`pub_date`,`free_trail`,`chapter_id`,`course_id`,`is_show_list`,`lesson`)
 VALUES
(1,1,0,'2019-08-13 07:27:06.873098','2019-08-13 07:27:06.873149','flask基本介绍',1,0,'http://www.baidu.com','3:00','2019-08-13 07:27:06.873188',1,1,1,1,1),
(2,1,0,'2019-08-13 07:27:27.408740','2019-08-13 07:27:27.408766','flask的优缺点',2,2,'http://www.baidu.com','3:30','2019-08-13 07:27:27.408798',1,1,1,0,2),
(3,1,0,'2019-08-13 07:27:45.659948','2019-08-13 07:27:45.659980','flask的安装',3,2,'http://www.baidu.com','5:00','2019-08-13 07:27:45.660016',0,1,1,1,3),
(13,1,0,'2019-08-13 07:27:06.873098','2019-08-13 07:27:06.873149','flask的项目搭建',4,2,'http://www.baidu.com','3:00','2019-08-13 07:27:06.873188',0,1,1,0,4),
(14,1,0,'2019-08-13 07:27:27.408740','2019-08-13 07:27:27.408766','flask的项目基本目录结构',5,2,'http://www.baidu.com','3:30','2019-08-13 07:27:27.408798',0,1,1,1,5),
(15,1,0,'2019-08-13 07:27:45.659948','2019-08-13 07:27:45.659980','flask的运行',6,2,'http://www.baidu.com','5:00','2019-08-13 07:27:45.660016',0,1,1,0,6),
(16,1,0,'2019-08-13 07:27:06.873098','2019-08-26 12:57:10.455292','django基本介绍',1,2,'7ec57198590152fd3a647d73e218e385_7','14:00','2019-08-13 07:27:06.873188',1,5,3,1,1),
(17,1,0,'2019-08-13 07:27:27.408740','2019-08-13 07:27:27.408766','django的优缺点',2,2,'http://www.baidu.com','3:30','2019-08-13 07:27:27.408798',1,5,3,0,2),
(18,1,0,'2019-08-13 07:27:45.659948','2019-08-14 02:13:52.517392','django的安装',3,2,'http://www.baidu.com','5:00','2019-08-13 07:27:45.660016',1,5,3,1,3),
(19,1,0,'2019-08-13 07:27:06.873098','2019-08-13 07:27:06.873149','django的项目搭建',4,2,'http://www.baidu.com','3:00','2019-08-13 07:27:06.873188',0,5,3,1,4),
(20,1,0,'2019-08-13 07:27:27.408740','2019-08-13 07:27:27.408766','django的项目基本目录结构',5,2,'http://www.baidu.com','3:30','2019-08-13 07:27:27.408798',0,5,3,1,5),
(21,1,0,'2019-08-13 07:27:45.659948','2019-08-13 07:27:45.659980','django的运行',6,2,'http://www.baidu.com','5:00','2019-08-13 07:27:45.660016',0,5,3,0,6),
(22,1,0,'2019-08-15 03:50:02.221829','2019-08-15 03:50:29.325498','路由的分类-命名绑定参数',1,2,'http://www.baidu.com','16:00','2019-08-15 03:50:02.221897',0,2,1,1,1);

4.客户端发送请求获取课程列表信息

Course.vue

<template>
  <div class="course">
    <Vheader></Vheader>
    <div class="main">
      <!-- 筛选条件 -->
      <div class="condition">
        <ul class="cate-list">
          <li class="title">课程分类:</li>
          <li :class="{this:category===0}" @click="category=0">全部</li>
          <li v-for="(value, index) in category_list" :key="value.id" @click="category=value.id" :class="{this:category===value.id}">{{value.name}}</li>

        </ul>


      </div>
      <!-- 课程列表 -->
      <div class="course-list">
        <div class="course-item" v-for="(course, courseindex) in course_list">
          <div class="course-image">
            <img :src="course.course_img" alt="">
          </div>
          <div class="course-info">
            <h3><router-link to="">{{course.name}}</router-link> <span><img src="/static/img/avatar1.svg" alt="">{{course.students}}人已加入学习</span></h3>
            <p class="teather-info">{{course.teacher.name}} {{course.teacher.signature}} {{course.teacher.title}} <span>共{{course.lessons}}
              课时/{{course.lessons===course.pub_lessons? '更新完成':`已更新${course.pub_lessons}课时`}}</span></p>
            <ul class="lesson-list">
              <li v-for="(lesson, lessonindex) in course.get_lessons" :key="lessonindex"><span class="lesson-title">0{{lessonindex+1}} | 第{{lesson.lesson}}节:{{lesson.name}}</span><span v-show="lesson.free_trail" class="free">免费</span></li>

            </ul>
            <div class="pay-box">
              <span class="discount-type">限时免费</span>
              <span class="discount-price">¥0.00元</span>
              <span class="original-price">原价:{{course.price}}元</span>
              <span class="buy-now">立即购买</span>
            </div>
          </div>
        </div>

      </div>
    </div>
    <Footer></Footer>
  </div>
</template>

<script>
  import Vheader from "./common/Vheader"
  import Footer from "./common/Footer"
  export default {
      name: "Course",
      data(){
        return{
          category:0,  //默认分类zhi
          category_list:[],
          course_list:[],
        }
      },
      components:{
        Vheader,
        Footer,
      },

      created() {
        this.get_categorys();
        this.get_course();

      },
      methods:{
        // 获取所有分类数据
        get_categorys(){
          this.$axios.get(`${this.$settings.Host}/course/categorys/`)
        .then((res)=>{
          //console.log(res.data);
          this.category_list = res.data;
        })
        },

        // 获取课程列表数据
        get_course(){
          this.$axios.get(`${this.$settings.Host}/course/courses/`)
          .then((res)=>{
            console.log(res.data);
            this.course_list = res.data;
          })
        }
      }


  }
</script>



<style scoped>
  .course{
    background: #f6f6f6;
  }
  .course .main{
    width: 1100px;
    margin: 35px auto 0;
  }
  .course .condition{
    margin-bottom: 35px;
    padding: 25px 30px 25px 20px;
    background: #fff;
    border-radius: 4px;
    box-shadow: 0 2px 4px 0 #f0f0f0;
  }
  .course .cate-list{
    border-bottom: 1px solid #333;
    border-bottom-color: rgba(51,51,51,.05);
    padding-bottom: 18px;
    margin-bottom: 17px;
  }
  .course .cate-list::after{
    content:"";
    display: block;
    clear: both;
  }
  .course .cate-list li{
    float: left;
    font-size: 16px;
    padding: 6px 15px;
    line-height: 16px;
    margin-left: 14px;
    position: relative;
    transition: all .3s ease;
    cursor: pointer;
    color: #4a4a4a;
    border: 1px solid transparent; /* transparent 透明 */
  }
  .course .cate-list .title{
    color: #888;
    margin-left: 0;
    letter-spacing: .36px;
    padding: 0;
    line-height: 28px;
  }
  .course .cate-list .this{
    color: #ffc210;
    border: 1px solid #ffc210!important;
    border-radius: 30px;
  }
  .course .ordering::after{
    content:"";
    display: block;
    clear: both;
  }
  .course .ordering ul{
    float: left;
  }
  .course .ordering ul::after{
    content:"";
    display: block;
    clear: both;
  }
  .course .ordering .condition-result{
    float: right;
    font-size: 14px;
    color: #9b9b9b;
    line-height: 28px;
  }
  .course .ordering ul li{
    float: left;
    padding: 6px 15px;
    line-height: 16px;
    margin-left: 14px;
    position: relative;
    transition: all .3s ease;
    cursor: pointer;
    color: #4a4a4a;
  }
  .course .ordering .title{
    font-size: 16px;
    color: #888;
    letter-spacing: .36px;
    margin-left: 0;
    padding:0;
    line-height: 28px;
  }
  .course .ordering .this{
    color: #ffc210;
  }
  .course .ordering .price{
    position: relative;
  }
  .course .ordering .price::before,
  .course .ordering .price::after{
    cursor: pointer;
    content:"";
    display: block;
    width: 0px;
    height: 0px;
    border: 5px solid transparent;
    position: absolute;
    right: 0;
  }
  .course .ordering .price::before{
    border-bottom: 5px solid #aaa;
    margin-bottom: 2px;
    top: 2px;
  }
  .course .ordering .price::after{
    border-top: 5px solid #aaa;
    bottom: 2px;
  }
  .course .course-item:hover{
    box-shadow: 4px 6px 16px rgba(0,0,0,.5);
  }
  .course .course-item{
    width: 1050px;
    background: #fff;
    padding: 20px 30px 20px 20px;
    margin-bottom: 35px;
    border-radius: 2px;
    cursor: pointer;
    box-shadow: 2px 3px 16px rgba(0,0,0,.1);
    /* css3.0 过渡动画 hover 事件操作 */
    transition: all .2s ease;
  }
  .course .course-item::after{
    content:"";
    display: block;
    clear: both;
  }
  /* 顶级元素 父级元素  当前元素{} */
  .course .course-item .course-image{
    float: left;
    width: 423px;
    height: 210px;
    margin-right: 30px;
  }
  .course .course-item .course-image img{
    width: 100%;
  }
  .course .course-item .course-info{
    float: left;
    width: 596px;
  }
  .course-item .course-info h3 {
    font-size: 26px;
    color: #333;
    font-weight: normal;
    margin-bottom: 8px;
  }
  .course-item .course-info h3 span{
    font-size: 14px;
    color: #9b9b9b;
    float: right;
    margin-top: 14px;
  }
  .course-item .course-info h3 span img{
      width: 11px;
      height: auto;
      margin-right: 7px;
  }
  .course-item .course-info .teather-info{
      font-size: 14px;
      color: #9b9b9b;
      margin-bottom: 14px;
      padding-bottom: 14px;
      border-bottom: 1px solid #333;
      border-bottom-color: rgba(51,51,51,.05);
  }
  .course-item .course-info .teather-info span{
      float: right;
  }
  .course-item .lesson-list::after{
      content:"";
      display: block;
      clear: both;
  }
  .course-item .lesson-list li {
    float: left;
    width: 44%;
    font-size: 14px;
    color: #666;
    padding-left: 22px;
    /* background: url("路径") 是否平铺 x轴位置 y轴位置 */
    background: url("/static/img/play-icon-gray.svg") no-repeat left 4px;
    margin-bottom: 15px;
  }
  .course-item .lesson-list li .lesson-title{
      /* 以下3句,文本内容过多,会自动隐藏,并显示省略符号 */
      text-overflow: ellipsis;
      overflow: hidden;
      white-space: nowrap;
      display:inline-block;
      max-width: 200px;
  }
  .course-item .lesson-list li:hover{
      background-image: url("/static/img/play-icon-yellow.svg");
      color: #ffc210;
  }
  .course-item .lesson-list li .free{
      width: 34px;
      height: 20px;
      color: #fd7b4d;
      vertical-align: super;
      margin-left: 10px;
      border: 1px solid #fd7b4d;
      border-radius: 2px;
      text-align: center;
      font-size: 13px;
      white-space: nowrap;
  }
  .course-item .lesson-list li:hover .free{
      color: #ffc210;
      border-color: #ffc210;
  }
  .course-item .pay-box::after{
    content:"";
    display: block;
    clear: both;
  }
  .course-item .pay-box .discount-type{
    padding: 6px 10px;
    font-size: 16px;
    color: #fff;
    text-align: center;
    margin-right: 8px;
    background: #fa6240;
    border: 1px solid #fa6240;
    border-radius: 10px 0 10px 0;
    float: left;
  }
  .course-item .pay-box .discount-price{
    font-size: 24px;
    color: #fa6240;
    float: left;
  }
  .course-item .pay-box .original-price{
    text-decoration: line-through;
    font-size: 14px;
    color: #9b9b9b;
    margin-left: 10px;
    float: left;
    margin-top: 10px;
  }
  .course-item .pay-box .buy-now{
    width: 120px;
    height: 38px;
    background: transparent;
    color: #fa6240;
    font-size: 16px;
    border: 1px solid #fd7b4d;
    border-radius: 3px;
    transition: all .2s ease-in-out;
    float: right;
    text-align: center;
    line-height: 38px;
  }
  .course-item .pay-box .buy-now:hover{
    color: #fff;
    background: #ffc210;
    border: 1px solid #ffc210;
  }
</style>

六、按照指定分类显示课程信息

在当前项目中安装 字段过滤排序

pip install django-filter

在settings/dev.py配置文件中增加过滤后端的设置:

INSTALLED_APPS = [
    ...
    'django_filters',  # 需要注册应用,
]

REST_FRAMEWORK = {
    ...
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

在视图中设置允许过滤的字段名和引入过滤字段核心类

class CourseView(ListAPIView):
    queryset = models.Course.objects.filter(is_deleted=False,is_show=True).order_by('id')
    serializer_class = CourseModelsSerializer
    filter_fields = ['course_category']

加上过滤之后的前端course组件

<template>
  <div class="course">
    <Vheader></Vheader>
    <div class="main">
      <!-- 筛选条件 -->
      <div class="condition">
        <ul class="cate-list">
          <li class="title">课程分类:</li>
          <li :class="{this:category===0}" @click="category=0">全部</li>
          <li v-for="(value, index) in category_list" :key="value.id" @click="category=value.id" :class="{this:category===value.id}">{{value.name}}</li>

        </ul>

      </div>
      <!-- 课程列表 -->
      <div class="course-list">
        <div class="course-item" v-for="(course, courseindex) in course_list">
          <div class="course-image">

            <img :src="course.course_img" alt="">

          </div>
          <div class="course-info">
            <h3><router-link to="">{{course.name}}</router-link> <span><img src="/static/img/avatar1.svg" alt="">{{course.students}}人已加入学习</span></h3>
            <p class="teather-info">{{course.teacher.name}} {{course.teacher.signature}} {{course.teacher.title}} <span>共{{course.lessons}}
              课时/{{course.lessons===course.pub_lessons? '更新完成':`已更新${course.pub_lessons}课时`}}</span></p>
            <ul class="lesson-list">
              <li v-for="(lesson, lessonindex) in course.get_lessons" :key="lessonindex"><span class="lesson-title">0{{lessonindex+1}} | 第{{lesson.lesson}}节:{{lesson.name}}</span><span v-show="lesson.free_trail" class="free">免费</span></li>

            </ul>
            <div class="pay-box">
              <span class="discount-type">限时免费</span>
              <span class="discount-price">¥0.00元</span>
              <span class="original-price">原价:{{course.price}}元</span>
              <span class="buy-now">立即购买</span>
            </div>
          </div>
        </div>

      </div>
    </div>
    <Footer></Footer>
  </div>
</template>

<script>
  import Vheader from "./common/Vheader"
  import Footer from "./common/Footer"
  export default {
      name: "Course",
      data(){
        return{
          category:0,  //默认分类zhi
          category_list:[],
          course_list:[],
          filters:{},
        }
      },
      components:{
        Vheader,
        Footer,
      },

      created() {
        this.get_categorys();
        this.get_course();

      },
      watch:{

        category(){
          if (this.category>0){
            this.filters['course_category'] = this.category;
          }else {
            this.filters={}
          }

          //console.log('>>>>>',this.fitlers)
          this.get_course(); //当分类数据发生变化时,出发获取数据的动作
        }
      },
      methods:{
        // 获取所有分类数据
        get_categorys(){
          this.$axios.get(`${this.$settings.Host}/course/categorys/`)
        .then((res)=>{
          //console.log(res.data);
          this.category_list = res.data;
        })
        },

        // 获取课程列表数据
        get_course(){


          this.$axios.get(`${this.$settings.Host}/course/courses/`,{
            params:this.filters,
          })
          .then((res)=>{
            //console.log(res.data);
            this.course_list = res.data;
          })
        }
      }


  }
</script>



<style scoped>
  .course{
    background: #f6f6f6;
  }
  .course .main{
    width: 1100px;
    margin: 35px auto 0;
  }
  .course .condition{
    margin-bottom: 35px;
    padding: 25px 30px 25px 20px;
    background: #fff;
    border-radius: 4px;
    box-shadow: 0 2px 4px 0 #f0f0f0;
  }
  .course .cate-list{
    border-bottom: 1px solid #333;
    border-bottom-color: rgba(51,51,51,.05);
    padding-bottom: 18px;
    margin-bottom: 17px;
  }
  .course .cate-list::after{
    content:"";
    display: block;
    clear: both;
  }
  .course .cate-list li{
    float: left;
    font-size: 16px;
    padding: 6px 15px;
    line-height: 16px;
    margin-left: 14px;
    position: relative;
    transition: all .3s ease;
    cursor: pointer;
    color: #4a4a4a;
    border: 1px solid transparent; /* transparent 透明 */
  }
  .course .cate-list .title{
    color: #888;
    margin-left: 0;
    letter-spacing: .36px;
    padding: 0;
    line-height: 28px;
  }
  .course .cate-list .this{
    color: #ffc210;
    border: 1px solid #ffc210!important;
    border-radius: 30px;
  }
  .course .ordering::after{
    content:"";
    display: block;
    clear: both;
  }
  .course .ordering ul{
    float: left;
  }
  .course .ordering ul::after{
    content:"";
    display: block;
    clear: both;
  }
  .course .ordering .condition-result{
    float: right;
    font-size: 14px;
    color: #9b9b9b;
    line-height: 28px;
  }
  .course .ordering ul li{
    float: left;
    padding: 6px 15px;
    line-height: 16px;
    margin-left: 14px;
    position: relative;
    transition: all .3s ease;
    cursor: pointer;
    color: #4a4a4a;
  }
  .course .ordering .title{
    font-size: 16px;
    color: #888;
    letter-spacing: .36px;
    margin-left: 0;
    padding:0;
    line-height: 28px;
  }
  .course .ordering .this{
    color: #ffc210;
  }
  .course .ordering .price{
    position: relative;
  }
  .course .ordering .price::before,
  .course .ordering .price::after{
    cursor: pointer;
    content:"";
    display: block;
    width: 0px;
    height: 0px;
    border: 5px solid transparent;
    position: absolute;
    right: 0;
  }
  .course .ordering .price::before{
    border-bottom: 5px solid #aaa;
    margin-bottom: 2px;
    top: 2px;
  }
  .course .ordering .price::after{
    border-top: 5px solid #aaa;
    bottom: 2px;
  }
  .course .course-item:hover{
    box-shadow: 4px 6px 16px rgba(0,0,0,.5);
  }
  .course .course-item{
    width: 1050px;
    background: #fff;
    padding: 20px 30px 20px 20px;
    margin-bottom: 35px;
    border-radius: 2px;
    cursor: pointer;
    box-shadow: 2px 3px 16px rgba(0,0,0,.1);
    /* css3.0 过渡动画 hover 事件操作 */
    transition: all .2s ease;
  }
  .course .course-item::after{
    content:"";
    display: block;
    clear: both;
  }
  /* 顶级元素 父级元素  当前元素{} */
  .course .course-item .course-image{
    float: left;
    width: 423px;
    height: 210px;
    margin-right: 30px;
  }
  .course .course-item .course-image img{
    width: 100%;
  }
  .course .course-item .course-info{
    float: left;
    width: 596px;
  }
  .course-item .course-info h3 {
    font-size: 26px;
    color: #333;
    font-weight: normal;
    margin-bottom: 8px;
  }
  .course-item .course-info h3 span{
    font-size: 14px;
    color: #9b9b9b;
    float: right;
    margin-top: 14px;
  }
  .course-item .course-info h3 span img{
      width: 11px;
      height: auto;
      margin-right: 7px;
  }
  .course-item .course-info .teather-info{
      font-size: 14px;
      color: #9b9b9b;
      margin-bottom: 14px;
      padding-bottom: 14px;
      border-bottom: 1px solid #333;
      border-bottom-color: rgba(51,51,51,.05);
  }
  .course-item .course-info .teather-info span{
      float: right;
  }
  .course-item .lesson-list::after{
      content:"";
      display: block;
      clear: both;
  }
  .course-item .lesson-list li {
    float: left;
    width: 44%;
    font-size: 14px;
    color: #666;
    padding-left: 22px;
    /* background: url("路径") 是否平铺 x轴位置 y轴位置 */
    background: url("/static/img/play-icon-gray.svg") no-repeat left 4px;
    margin-bottom: 15px;
  }
  .course-item .lesson-list li .lesson-title{
      /* 以下3句,文本内容过多,会自动隐藏,并显示省略符号 */
      text-overflow: ellipsis;
      overflow: hidden;
      white-space: nowrap;
      display:inline-block;
      max-width: 200px;
  }
  .course-item .lesson-list li:hover{
      background-image: url("/static/img/play-icon-yellow.svg");
      color: #ffc210;
  }
  .course-item .lesson-list li .free{
      width: 34px;
      height: 20px;
      color: #fd7b4d;
      vertical-align: super;
      margin-left: 10px;
      border: 1px solid #fd7b4d;
      border-radius: 2px;
      text-align: center;
      font-size: 13px;
      white-space: nowrap;
  }
  .course-item .lesson-list li:hover .free{
      color: #ffc210;
      border-color: #ffc210;
  }
  .course-item .pay-box::after{
    content:"";
    display: block;
    clear: both;
  }
  .course-item .pay-box .discount-type{
    padding: 6px 10px;
    font-size: 16px;
    color: #fff;
    text-align: center;
    margin-right: 8px;
    background: #fa6240;
    border: 1px solid #fa6240;
    border-radius: 10px 0 10px 0;
    float: left;
  }
  .course-item .pay-box .discount-price{
    font-size: 24px;
    color: #fa6240;
    float: left;
  }
  .course-item .pay-box .original-price{
    text-decoration: line-through;
    font-size: 14px;
    color: #9b9b9b;
    margin-left: 10px;
    float: left;
    margin-top: 10px;
  }
  .course-item .pay-box .buy-now{
    width: 120px;
    height: 38px;
    background: transparent;
    color: #fa6240;
    font-size: 16px;
    border: 1px solid #fd7b4d;
    border-radius: 3px;
    transition: all .2s ease-in-out;
    float: right;
    text-align: center;
    line-height: 38px;
  }
  .course-item .pay-box .buy-now:hover{
    color: #fff;
    background: #ffc210;
    border: 1px solid #ffc210;
  }
</style>

七、加分页

Course.vue组件

<template>
  <div class="course">
    <Vheader></Vheader>
    <div class="main">
      <!-- 筛选条件 -->
      <div class="condition">
        <ul class="cate-list">
          <li class="title">课程分类:</li>
          <li :class="{this: category===0}" @click="category=0">全部</li>
          <li v-for="(value, index) in category_list" :key="value.id" @click="category=value.id" :class="{this:category===value.id}">{{value.name}}</li>

        </ul>



      </div>
      <!-- 课程列表 -->
      <div class="course-list">
        <div class="course-item" v-for="(course, courseindex) in course_list">
          <div class="course-image">
            <img :src="course.course_img" alt="">
          </div>
          <div class="course-info">
            <h3><router-link to="">{{ course.name }}</router-link> <span><img src="/static/img/avatar1.svg" alt="">{{course.students}}人已加入学习</span></h3>
            <p class="teather-info">{{course.teacher.name}} {{ course.teacher.signature }} {{course.teacher.title}} <span>共{{ course.lessons }}课时/{{course.lessons===course.pub_lessons? '更新完成':`已更新${course.pub_lessons}课时`}}</span></p>
            <ul class="lesson-list">
              <li v-for="(lesson, lessonindex) in course.get_lessons" :key="lessonindex"><span class="lesson-title">0{{lessonindex+1}} | 第{{lesson.lesson}}节:{{lesson.name}}</span> <span v-show="lesson.free_trail" class="free">免费</span></li>

            </ul>
            <div class="pay-box">
              <span class="discount-type">限时免费</span>
              <span class="discount-price">¥0.00元</span>
              <span class="original-price">原价:{{course.price}}元</span>
              <span class="buy-now">立即购买</span>
            </div>
          </div>
        </div>

      </div>
    </div>
    <div class="c1">
      <el-pagination
        background
        :page-size="2"
        layout="prev, pager, next, sizes, jumper"
        :page-sizes="[2, 5, 10, 15, 20]"
        @current-change="handleCurrentChange"
        @size-change="handleSizeChange"
        :total="total">
      </el-pagination>
    </div>
    <Footer></Footer>
  </div>
</template>

<script>
  import Vheader from "./common/Vheader"
  import Footer from "./common/Footer"
  export default {
      name: "Course",
      data(){
        return{
          category:0,
          category_list:[],
          course_list:[],
          filters:{},
          total:0,
        }
      },
    components:{
      Vheader,
      Footer,
    },
    created() {
        this.get_categorys();
        this.get_course();
    },
    watch:{
      category(){
        if (this.category>0){
          this.filters['course_category'] = this.category;
        }else {
          this.filters={}
        }
        this.get_course();
      }
    },
    methods:{
      handleSizeChange(val){
        this.filters['size'] = val
        this.get_course();
      },
      handleCurrentChange(val){
        this.filters['page'] = val
        this.get_course();
      },
        // 获取所有分类数据
      get_categorys(){
        this.$axios.get(`${this.$settings.Host}/course/categorys/`)
        .then((res)=>{
          this.category_list = res.data;
        })
        },
      // 获取课程列表数据
      get_course(){
        this.$axios.get(`${this.$settings.Host}/course/courses`,{
          params:this.filters,
        })
        .then((res)=>{
          // console.log(res.data);
          this.total = res.data.count
          this.course_list = res.data.results;
        })
      }
    }

  }
</script>



<style scoped>
  .c1 /deep/ .el-pagination{
    text-align: center;
    font-size: 40px;
  }
  .course{
    background: #f6f6f6;
  }
  .course .main{
    width: 1100px;
    margin: 35px auto 0;
  }
  .course .condition{
    margin-bottom: 35px;
    padding: 25px 30px 25px 20px;
    background: #fff;
    border-radius: 4px;
    box-shadow: 0 2px 4px 0 #f0f0f0;
  }
  .course .cate-list{
    border-bottom: 1px solid #333;
    border-bottom-color: rgba(51,51,51,.05);
    padding-bottom: 18px;
    margin-bottom: 17px;
  }
  .course .cate-list::after{
    content:"";
    display: block;
    clear: both;
  }
  .course .cate-list li{
    float: left;
    font-size: 16px;
    padding: 6px 15px;
    line-height: 16px;
    margin-left: 14px;
    position: relative;
    transition: all .3s ease;
    cursor: pointer;
    color: #4a4a4a;
    border: 1px solid transparent; /* transparent 透明 */
  }
  .course .cate-list .title{
    color: #888;
    margin-left: 0;
    letter-spacing: .36px;
    padding: 0;
    line-height: 28px;
  }
  .course .cate-list .this{
    color: #ffc210;
    border: 1px solid #ffc210!important;
    border-radius: 30px;
  }
  .course .ordering::after{
    content:"";
    display: block;
    clear: both;
  }
  .course .ordering ul{
    float: left;
  }
  .course .ordering ul::after{
    content:"";
    display: block;
    clear: both;
  }
  .course .ordering .condition-result{
    float: right;
    font-size: 14px;
    color: #9b9b9b;
    line-height: 28px;
  }
  .course .ordering ul li{
    float: left;
    padding: 6px 15px;
    line-height: 16px;
    margin-left: 14px;
    position: relative;
    transition: all .3s ease;
    cursor: pointer;
    color: #4a4a4a;
  }
  .course .ordering .title{
    font-size: 16px;
    color: #888;
    letter-spacing: .36px;
    margin-left: 0;
    padding:0;
    line-height: 28px;
  }
  .course .ordering .this{
    color: #ffc210;
  }
  .course .ordering .price{
    position: relative;
  }
  .course .ordering .price::before,
  .course .ordering .price::after{
    cursor: pointer;
    content:"";
    display: block;
    width: 0px;
    height: 0px;
    border: 5px solid transparent;
    position: absolute;
    right: 0;
  }
  .course .ordering .price::before{
    border-bottom: 5px solid #aaa;
    margin-bottom: 2px;
    top: 2px;
  }
  .course .ordering .price::after{
    border-top: 5px solid #aaa;
    bottom: 2px;
  }
  .course .course-item:hover{
    box-shadow: 4px 6px 16px rgba(0,0,0,.5);
  }
  .course .course-item{
    width: 1050px;
    background: #fff;
    padding: 20px 30px 20px 20px;
    margin-bottom: 35px;
    border-radius: 2px;
    cursor: pointer;
    box-shadow: 2px 3px 16px rgba(0,0,0,.1);
    /* css3.0 过渡动画 hover 事件操作 */
    transition: all .2s ease;
  }
  .course .course-item::after{
    content:"";
    display: block;
    clear: both;
  }
  /* 顶级元素 父级元素  当前元素{} */
  .course .course-item .course-image{
    float: left;
    width: 423px;
    height: 210px;
    margin-right: 30px;
  }
  .course .course-item .course-image img{
    width: 100%;
  }
  .course .course-item .course-info{
    float: left;
    width: 596px;
  }
  .course-item .course-info h3 {
    font-size: 26px;
    color: #333;
    font-weight: normal;
    margin-bottom: 8px;
  }
  .course-item .course-info h3 span{
    font-size: 14px;
    color: #9b9b9b;
    float: right;
    margin-top: 14px;
  }
  .course-item .course-info h3 span img{
      width: 11px;
      height: auto;
      margin-right: 7px;
  }
  .course-item .course-info .teather-info{
      font-size: 14px;
      color: #9b9b9b;
      margin-bottom: 14px;
      padding-bottom: 14px;
      border-bottom: 1px solid #333;
      border-bottom-color: rgba(51,51,51,.05);
  }
  .course-item .course-info .teather-info span{
      float: right;
  }
  .course-item .lesson-list::after{
      content:"";
      display: block;
      clear: both;
  }
  .course-item .lesson-list li {
    float: left;
    width: 44%;
    font-size: 14px;
    color: #666;
    padding-left: 22px;
    /* background: url("路径") 是否平铺 x轴位置 y轴位置 */
    background: url("/static/img/play-icon-gray.svg") no-repeat left 4px;
    margin-bottom: 15px;
  }
  .course-item .lesson-list li .lesson-title{
      /* 以下3句,文本内容过多,会自动隐藏,并显示省略符号 */
      text-overflow: ellipsis;
      overflow: hidden;
      white-space: nowrap;
      display:inline-block;
      max-width: 200px;
  }
  .course-item .lesson-list li:hover{
      background-image: url("/static/img/play-icon-yellow.svg");
      color: #ffc210;
  }
  .course-item .lesson-list li .free{
      width: 34px;
      height: 20px;
      color: #fd7b4d;
      vertical-align: super;
      margin-left: 10px;
      border: 1px solid #fd7b4d;
      border-radius: 2px;
      text-align: center;
      font-size: 13px;
      white-space: nowrap;
  }
  .course-item .lesson-list li:hover .free{
      color: #ffc210;
      border-color: #ffc210;
  }
  .course-item .pay-box::after{
    content:"";
    display: block;
    clear: both;
  }
  .course-item .pay-box .discount-type{
    padding: 6px 10px;
    font-size: 16px;
    color: #fff;
    text-align: center;
    margin-right: 8px;
    background: #fa6240;
    border: 1px solid #fa6240;
    border-radius: 10px 0 10px 0;
    float: left;
  }
  .course-item .pay-box .discount-price{
    font-size: 24px;
    color: #fa6240;
    float: left;
  }
  .course-item .pay-box .original-price{
    text-decoration: line-through;
    font-size: 14px;
    color: #9b9b9b;
    margin-left: 10px;
    float: left;
    margin-top: 10px;
  }
  .course-item .pay-box .buy-now{
    width: 120px;
    height: 38px;
    background: transparent;
    color: #fa6240;
    font-size: 16px;
    border: 1px solid #fd7b4d;
    border-radius: 3px;
    transition: all .2s ease-in-out;
    float: right;
    text-align: center;
    line-height: 38px;
  }
  .course-item .pay-box .buy-now:hover{
    color: #fff;
    background: #ffc210;
    border: 1px solid #ffc210;
  }
</style>

后台分页视图接口

from django.shortcuts import render
from . import models
# Create your views here.
from rest_framework.generics import ListAPIView
from .serializers import CourseCategoryModelSerializer,CourseModelsSerializer
from lyapi.apps.course.pagenation import StandardPageNumberPagination


class CategoryView(ListAPIView):

    queryset = models.CourseCategory.objects.filter(is_deleted=False, is_show=True)
    serializer_class = CourseCategoryModelSerializer

# 加过滤
class CourseView(ListAPIView):
    queryset = models.Course.objects.filter(is_deleted=False, is_show=True).order_by('id')
    serializer_class = CourseModelsSerializer
    filter_fields = ['course_category']
    pagination_class = StandardPageNumberPagination

course/pagenation.py

from rest_framework.pagination import PageNumberPagination
class StandardPageNumberPagination(PageNumberPagination):
    # 默认每一页显示的数据量
    page_size = 2
    # 允许客户端通过get参数来控制每一页的数据量
    page_size_query_param = "size"
    max_page_size = 10  #客户端通过size指定获取数据的条数时,最大不能超过多少
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值