1.Vue结构
App.vue
<template> <div id="app"> <router-link to="/index">首页</router-link> <router-link to="/course">课程</router-link> <router-link to="/micro">微职位</router-link> <router-link to="/news">深科技</router-link> <router-view/> </div> </template> <script> export default { name: 'App' } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; color: #2c3e50; } </style>
这里进行利路由设置,那么需要在index中进行挂载
import Vue from 'vue' import Router from 'vue-router' // 导入模块 import Index from '../components/Index' import Course from '../components/Course' import Micro from '../components/Micro' import News from '../components/News' import Detail from '../components/Detail' Vue.use(Router); export default new Router({ routes: [ { path: '/index', name: 'index', component: Index }, { path: '/course', name: 'course', component: Course }, { path: '/detail/:id', name: 'detail', component: Detail }, { path: '/micro', name: 'micro', component: Micro },{ path: '/news', name: 'news', component: News } ], mode:'history' //取出url里面的#号 })
在main.js中导入axios,和ajax一样。

import Vue from 'vue' import App from './App' import router from './router' import axios from 'axios' //在vue的全局变量中设置了$axios=axios //以后每个组件使用时:this.$axios Vue.prototype.$axios=axios; Vue.config.productionTip = false; /* eslint-disable no-new */ new Vue({ el: '#app', router, components: { App }, template: '<App/>' })
在课程中向后端发送请求并用v-for进行展示
<template> <div> <h1>课程列表</h1> <ul v-for="row in courseList"> <li><router-link :to="{name:'detail',params:{id:row.id}}">{{row.title}}</router-link></li>
//这里利用:to来传入一个课程的ID,这样可以知道点击哪个课程的详细页。 </ul> </div> </template> <script> export default { name: "course", data(){ return { msg:"课程", courseList:[ ] } }, mounted:function () { //vue页面刚加载时执行 this.initCourse() }, methods:{ initCourse:function () { //去通过ajax向接口发送请求并获取课程列表数据 //axios/jquery //第一步在main.js中配置 //第二部使用axios发送请求 var that = this; this.$axios.request({ url:'http://127.0.0.1:8000/api/v1/course/', method:'GET', }).then(function(ret){ //ajax请求发送成功后,获取响应内容 console.log(ret.data) if (ret.data.code ===1000){ that.courseList=ret.data.data } }).catch(function(ret){ //上面发生异常执行这个 }) } } } </script> <style scoped> </style>
这边设置好后,在Detail.vue中
<template> <h1>课程详细页面</h1> </template> <script> export default { name: "detail", data(){ return { } }, mounted(){ console.log(this); #Vue对象 console.log(this.$route.params.id) #通过这个可以拿到这个ID, } } </script> <style scoped> </style>
这里的数据是假数据,所以应该真正的去后端创建数据表,并且编写API接口
1.创建models表

from django.db import models # Create your models here. class Course(models.Model): ''' 课程表 ''' title=models.CharField(max_length=32,verbose_name="课程名称") course_img = models.CharField(max_length=64,verbose_name="课程图片") level_choices=( (1,'初级'), (2,'中级'), (3,'高级'), ) level=models.IntegerField(verbose_name="课程难易",choices=level_choices,default=1) def __str__(self): return self.title class CourseDetail(models.Model): ''' 课程详细 ''' course = models.OneToOneField(to="Course", on_delete=models.CASCADE) slogon=models.CharField(max_length=255,verbose_name="口号") why=models.CharField(max_length=255,verbose_name="为什么要学") recommend_courses=models.ManyToManyField(to="Course",verbose_name="推荐课程",related_name='rc') def __str__(self): return "课程详细"+self.course.title class Chapter(models.Model): ''' 章节表 ''' num=models.IntegerField(verbose_name="第几章") name=models.CharField(max_length=32,verbose_name="章节名称") coursedetail=models.ForeignKey("Course",on_delete=models.CASCADE,verbose_name="所属课程") def __str__(self): return self.name
2.做一个序列化,并返回数据
from rest_framework.views import APIView from rest_framework.response import Response from api import models from rest_framework import serializers class CourseSerializer(serializers.ModelSerializer): class Meta: model=models.Course fields="__all__" from rest_framework.viewsets import GenericViewSet,ViewSetMixin class CourseView(ViewSetMixin,APIView): def list(self,request,*args,**kwargs): ''' 课程列表接口 :param request: :param args: :param kwargs: :return: ''' ret = {'code': 1000, "data": None} try: query=models.Course.objects.all() ser = CourseSerializer(instance=query,many=True) ret["data"]=ser.data except Exception as e: ret["code"]=1001 ret["error"]="获取课程失败" return Response(ret) def retrieve(self,request,*args,**kwargs): ''' 课程详细的接口 :param request: :param args: :param kwargs: :return: ''' ret = {'code': 1000, "data": None} try: pk=kwargs.get('pk') obj = models.Course.objects.filter(id=pk).first() ser = CourseSerializer(instance=obj,many=False) ret["data"] = ser.data except Exception as e: ret["code"]=1001 ret["error"]="获取课程失败" return Response(ret)
3.因为后面的url使用了get不同需求的状态,所以是重写了as_view(),所以类中继承的是
ViewSetMixin,zhe这样的话,就可以对都是get请求使用同一个类,做出不同的响应,有PK的使用retrieve方法,没有的使用list方法。
urlpatterns = [ # url(r'^course/$', course.CourseView.as_view()), # url(r'^course/(?P<pk>\d+)/$', course.CourseView.as_view()), #这种方案必须继承ViewSetMixin,它重写了as_view,可以往里添加参数 url(r'^course/$', course.CourseView.as_view({"get":"list"})), url(r'^course/(?P<pk>\d+)/$', course.CourseView.as_view({"get":"retrieve"})), ]
最后是API接口
1.查询所有课程: http://127.0.0.1:8000/api/v1/course/ 2.查询单个课程: http://127.0.0.1:8000/api/v1/course/1/
但是因为有了新的需求,所以需要重新的来进行更多的定制。
from rest_framework.views import APIView from rest_framework.response import Response from api import models from rest_framework import serializers class CourseSerializer(serializers.ModelSerializer): class Meta: model=models.Course fields="__all__" class CourseDetailSerializer(serializers.ModelSerializer): #o2o fk,choice title=serializers.CharField(source='course.title') #只能这里通过跨表拿到以后,在下面展示 img=serializers.CharField(source='course.course_img') level=serializers.CharField(source='course.get_level_display') #通过get_level_display方法拿到choice对应的值,如果是方法需要加(),这里反射所以不加 #m2m recommends = serializers.SerializerMethodField() #这个因为是多对多字段,所以需要通过一个方法来拿到 class Meta: model=models.CourseDetail fields=['course','title','recommends','level','img','slogon','why'] #想要展示的字段 depth:1 #展示深度,这个就是说这个表如果有跟别的表跨表就会把那个表拿过来也序列化,深度越大,越往后关联的越多。 def get_recommends(self,obj): #这里通过拿到这个queryset #获取推荐的所有课程 query=obj.recommend_courses.all() return [{'id':row.id,'title':row.title} for row in query] #通过列表解析式将这个进行拆分成如下格式。 from rest_framework.viewsets import GenericViewSet,ViewSetMixin class CourseView(ViewSetMixin,APIView): def list(self,request,*args,**kwargs): ''' 课程列表接口 :param request: :param args: :param kwargs: :return: ''' ret = {'code': 1000, "data": None} try: query=models.Course.objects.all() ser = CourseSerializer(instance=query,many=True) ret["data"]=ser.data except Exception as e: ret["code"]=1001 ret["error"]="获取课程失败" return Response(ret) def retrieve(self,request,*args,**kwargs): ''' 课程详细的接口 :param request: :param args: :param kwargs: :return: ''' ret = {'code': 1000, "data": None} try: pk=kwargs.get('pk') obj = models.CourseDetail.objects.filter(course_id=pk).first() #这里需要做的是这里会CourseDetail里面通过course_id跨表到course表 ser = CourseDetailSerializer(instance=obj,many=False) #这里使用了新的序列化类。 ret["data"] = ser.data except Exception as e: ret["code"]=1001 ret["error"]="获取课程失败" return Response(ret)
这里获取具体每一个课程想要获得更多的信息,而不是局限于那个课程表,所以建立了一个
CourseDetailSerializer的序列化类。
最终效果:
最后做了一点优化以及解耦的分离:

# Author:Jesi # Time : 2018/10/16 14:21 from rest_framework import serializers from api import models class CourseSerializer(serializers.ModelSerializer): ''' 课程序列化 ''' level=serializers.CharField(source='get_level_display') class Meta: model=models.Course fields='__all__' class CourseDetailSerializer(serializers.ModelSerializer): ''' 课程详细序列化 ''' #o2o fk,choice title=serializers.CharField(source='course.title') img=serializers.CharField(source='course.course_img') level=serializers.CharField(source='course.get_level_display') #m2m recommends = serializers.SerializerMethodField() chapter = serializers.SerializerMethodField() class Meta: model=models.CourseDetail fields=['course','title','recommends','level','chapter','img','slogon','why'] depth:1 def get_recommends(self,obj): #获取推荐的所有课程 query=obj.recommend_courses.all() return [{'id':row.id,'title':row.title} for row in query] def get_chapter(self,obj): #获取推荐的章节 query=obj.course.chapter_set.all() print(query) return [{'id':row.num,'name':row.name} for row in query]
在前端Vue里面对详情页进行了数据传送:

<template> <div> <h1>课程详细页面</h1> <p>课程标题:{{detail.title}}</p> <p>图片:{{detail.img}}</p> <p>课程难度:{{detail.level}}</p> <p>课程口号:{{detail.slogon}}</p> <p>为什么要学?{{detail.why}}</p> <div> 章节: <ul v-for="item in detail.charter"> <li>{{item.name}}</li> </ul> </div> <div> 推荐课程: <ul v-for="item in detail.recommends"> <li>{{item.title}}</li> </ul> </div> </div> </template> <script> export default { name: "detail", data(){ return { detail:{ charter:[], course:null, level:null, img:null, title:null, slogon:null, why:null, recommends:[] } } }, mounted(){ this.initDetail() }, methods:{ initDetail(){ var nid=this.$route.params.id; var that = this; this.$axios.request({ url:'http://127.0.0.1:8000/api/v1/course/'+nid+'/', method:"GET", }).then(function (arg) { if (arg.data.code ===1000){ console.log(arg.data); that.detail=arg.data.data }else{ alert(arg.data.error) } }) } } } </script> <style scoped> </style>