01 - vue + rest framework - v1.0、v1.1 - 课程列表、课程详细列表

code

https://github.com/alice-bj/luffy/releases

一、V1.0 知识点

    1. 渲染器
       规定页面显示的效果(无用)
    2. 版本 
        原理:要了解
        使用:
            1. 添加配置
                REST_FRAMEWORK = {
                    
                    .... 
                    
                    'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
                    'ALLOWED_VERSIONS':['v1','v2'], # 允许的版本
                    'VERSION_PARAM':'version', # 参数
                    'DEFAULT_VERSION':'v1', # 默认版本
                    ....
                }

            2. 设置路由 
                
                s9luffycity/urls.py
                    urlpatterns = [
                        #url(r'^admin/', admin.site.urls),
                        url(r'^api/(?P<version>\w+)/', include('api.urls')),
                    ]
                
                api/urls.py 
                    urlpatterns = [
                        url(r'^course/$', course.CourseView.as_view()),
                    ]
            
            3. 获取版本 
                request.version 获取版本  
            
    
    3. vue+rest framework
        vue: 
            - 路由 + 组件 
            - axios发送ajax请求
            - that 
        api:
            - 跨域   
            
        补充:
            - 域名不同
            - 端口不同 
        cors:
            本质设置响应头    跨域的简单请求和复杂请求
                    
                    # 允许你的域名来获取我的数据
                    response['Access-Control-Allow-Origin'] = "*"

                    # 允许你携带Content-Type请求头
                    response['Access-Control-Allow-Headers'] = "Content-Type"

                    # 允许你发送DELETE,PUT
                    response['Access-Control-Allow-Methods'] = "DELETE,PUT"
        
笔记

效果图

1. 版本:

1. 添加配置
    REST_FRAMEWORK = {
        
        .... 
        
        'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
        'ALLOWED_VERSIONS':['v1','v2'], # 允许的版本
        'VERSION_PARAM':'version', # 参数
        'DEFAULT_VERSION':'v1', # 默认版本
        ....
    }

2. 设置路由 
    
    s9luffycity/urls.py
        urlpatterns = [
            #url(r'^admin/', admin.site.urls),
            url(r'^api/(?P<version>\w+)/', include('api.urls')),
        ]
    
    api/urls.py 
        urlpatterns = [
            url(r'^course/$', course.CourseView.as_view()),
        ]

3. 获取版本 
    request.version 获取版本  

 

2. 跨域的简单请求和复杂请求

cors.py

from django.utils.deprecation import MiddlewareMixin

class CORSMiddleware(MiddlewareMixin):
    def process_response(self,request,response):
        # 允许你的域名来访问
        response['Access-Control-Allow-Origin'] = "*"
        # 允许你携带 Content-Type 请求头 不能写*
        response['Access-Control-Allow-Headers'] = 'Content-Type'
        # 允许你发送 DELETE PUT请求
        response['Access-Control-Allow-Methods'] = 'DELETE,PUT'
        return response
        
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    ... ...
       
    'api.cors.CORSMiddleware'
]    

 

二、V1.1 知识点

s9day105 

内容回顾:
    - restful 规范(10- django rest framework框架(10- 跨域
    - 为什么会有跨域?
    - 绕过浏览器同源策略就可以跨域。
        - jsonp
            动态创建script标签
            同源策略会阻止ajax请求;不阻止具有src属性的标签
            <script src='xxxx'></script>
        - cors
            设置响应头
            
今日内容:
    - vue 
    - api
    
    
    
内容详细:
    1. vue
        - 课程列表
        - 课程详细
        
        - 任务:    
            - 课程表 
                id   title  course_img   level(choices) 
            - 课程详细(one2one  课程 )
                id   why  推荐课程
            - 章节 
                id    name  
        - 功能:
            a. 课程列表显示图片
            
            b. 课程详细显示:
                - 为什么要学习这个课程
                - 所有推荐课程
                - 所有章节
                 
    2. api
        1. 查询所有的课程
            http://127.0.0.1:8000/api/v1/course/
            练习:level变中文
            
        2. 查询课程详细 
            http://127.0.0.1:8000/api/v1/course/1/
            - 路由 as_view 是否添加参数,取决于视图继承的类
            - 序列化
                - depth
                - source
                - 自定义method
            
            练习:显示该课程相关的所有章节
            
    this补充:
题目1:
    var name = '景女神'

    function Foo(name,age){
        this.name = name;
        this.age = age;
        this.getName = function(){
            console.log(this.name); # 文州
            
            (function(){
                console.log(this.name); # 女神
            })()
            
        }
    }

    obj = new Foo('文州',19)
    obj.getName()

题目2:
    var name = '景女神'

    function Foo(name,age){
        this.name = name;
        this.age = age;
        this.getName = function(){
            console.log(this.name); # 文州
            var that = this 
            (function(){
                console.log(that.name); # 文州
            })()
            
        }
    }

    obj = new Foo('文州',19)

    obj.getName()

题目3:
    var name = '景女神'
    obj = {
        name:'文州',
        age: 19,
        getName:function(){
            console.log(this.name); # 文州
            var that = this 
            (function(){
                console.log(that.name); # 文州
            })()
        }
    }
    obj.getName()


作业:
    1. 前后端流程
    2. 图片 
    3. CC视频账号
    4. git相关
        - 安装git软件
        - 注册github账号
    
    
    
    
笔记

效果图 

 

1. 前端 - axios 发送ajax请求

通过ajax向接口发起请求,并获取课程列表
axios 可以发ajax请求 npm install axios --save
 1. 在main.js中配置
 2. 使用axios发送请求

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import axios from 'axios'

// 在vue的全局变量中设置了 $axios 
// 以后组件 使用 this.$axios
Vue.prototype.$axios = axios
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})
main.js
<template>
    <div>
        <h2>课程列表</h2>
        <div v-for="row in courseList">
            <div style="width: 350px; float: left;">
                <img src="">
                <h3><router-link :to="{name:'detail',params:{id:row.id}}">{{row.title}}</router-link></h3>
                <p>{{row.level}}</p>
            </div>
        </div>
    </div>
</template>

<script>
    export default{
        name:'course',
        data(){
            return {
                msg:'course',
                courseList:[],
            }
        },
        // 页面加载时自动执行
        mounted:function(){
            this.initCourse()
        },
        methods:{
            initCourse:function(){
                //通过ajax向接口发动请求,并获取课程列表
                // axios 可以发ajax请求  npm install axios --save
                // 1. 在main.js中配置
                // 2. 使用axios发送请求
                var that = this
                
                this.$axios.request({
                    url:'http://127.0.0.1:8000/api/v1/course/',
                    method:'GET'
                }).then(function(ret){
                    // ajax请求发送成功后,获得的响应内容
                    // ret.data
                    if(ret.data.code==1000){
                        that.courseList = ret.data.data
                        console.log(ret.data.data)
                    }else{
                        alert('获取数据失败')
                    }

                }).catch(function(ret){
                    //ajax请求失败后,获取响应的内容

                })

            }
        }
    }
</script>

<style scoped>
    
</style>
Course.vue
<template>
    <div>
        <p>{{detail.course}}</p>
        <p>{{detail.img}}</p>
        <p>{{detail.level}}</p>
        <p>{{detail.slogon}}</p>
        <p>{{detail.title}}</p>
        <p>{{detail.why}}</p>
        <div>
            <ul v-for='item in detail.chapters'>
                <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:{
                    course:null,
                    img:null,
                    level:null,
                    slogon:null,
                    title:null,
                    why:null,
                    chapters:[],
                    recommends:[]
                }
            }
        },
        mounted:function(){
            console.log(this.$route.params.id)
            this.initDetail()
        },
        methods:{
            initDetail:function(){
                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(ret){
                    if(ret.data.code==1000){
                        that.detail = ret.data.data
                    }else{
                        alert(ret.data.error)
                    }

                }).catch(function(ret){

                })
            }

        }
    }
</script>

<style scoped>
    
</style>
Detail.vue

 

2. 前端 - 链接带参数,并取消# 

mode:'history'   

path: '/detail/:id'

参数得使用:

Course.vue

<template>
    <div>
        <h2>课程列表</h2>
        <div v-for="row in courseList">
            <div style="width: 350px; float: left;">
                <img src="">
                <h3><router-link :to="{name:'detail',params:{id:row.id}}">{{row.title}}</router-link></h3>
                <p>{{row.level}}</p>
            </div>
        </div>
    </div>
</template>

 

3. 前端 - 页面获取id从接口取值

Detail.vue

<script>
    export default{
        name:'detail',
        data(){
            return {
                detail:{
                    course:null,
                    img:null,
                    level:null,
                    slogon:null,
                    title:null,
                    why:null,
                    chapters:[],
                    recommends:[]
                }
            }
        },  
     // 页面加载时 自动执行 mounted:
function(){ console.log(this.$route.params.id) this.initDetail() }, methods:{ initDetail:function(){ 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(ret){ if(ret.data.code==1000){ that.detail = ret.data.data }else{ alert(ret.data.error) } }).catch(function(ret){ }) } } } </script>

 

index.js

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'
})

 

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>

</style>

 

4. 后端 - 提供接口

    1.查询所有课程
        http://localhost:8000/api/v1/course/
    2.查询课程详细
        http://localhost:8000/api/v1/course/1/
            - 路由 as_view 是否添加参数,取决于视图继承的类
            - 序列化
                - depth
                - source
                - 自定义method

 

 

 

课程,课程详细 

from django.db import models

class Course(models.Model):
    """
    课程表
    """
    title = models.CharField(verbose_name="课程名称", max_length=32)
    course_img = models.CharField(verbose_name='课程图片', max_length=64)
    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")
    slogon = models.CharField(verbose_name="口号", max_length=255)
    why = models.CharField(verbose_name="为什么要学", max_length=255)
    recommend_courses = models.ManyToManyField(verbose_name="推荐课程", to="Course", related_name='rc')

    def __str__(self):
        return "课程详细:"+self.course.title


class Chapter(models.Model):
    """
    章节
    """
    num = models.IntegerField(verbose_name="第几章")
    name = models.CharField(verbose_name="章节名称", max_length=32)
    course = models.ForeignKey(verbose_name="所属课程", to="Course")

    def __str__(self):
        return self.name
models.py

 

urls.py

from django.conf.urls import url,include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/(?P<version>\w+)/', include('api.urls')),
]


------------------------------------
api/urls.py
from django.conf.urls import url
from api.views import course

urlpatterns = [
    # 方式一:
    # url(r'^course/$', course.CourseView.as_view()),
    # url(r'^course/(?P<pk>\d+)/$', course.CourseView.as_view()),

    # 方式二:
    url(r'^course/$', course.CourseView.as_view({"get": 'list'})),
    url(r'^course/(?P<pk>\d+)/$', course.CourseView.as_view({"get": "retrieve"})),

]

 

views/course.py

from rest_framework.views import APIView
from rest_framework.response import Response

from api.models import *
from api.serializers.course import CourseSerializers, CourseDetailSerializers

# 方式一:

# class CourseView(APIView):
#
#     def get(self,request,*args,**kwargs):
#         ret = {'code':1000, 'data':None}
#         try:
#             pk = kwargs.get('pk')
#             if pk:
#                 obj = Course.objects.filter(id=pk).first()
#                 ser = CourseSerializers(instance=obj,many=False)
#             else:
#                 course_list = Course.objects.all()
#                 ser = CourseSerializers(course_list,many=True)
#             ret['data'] = ser.data
#         except Exception as e:
#             ret['code'] = 1001,
#             ret['data'] = '获取课程失败'
#         return Response(ret)


# 方式二:
# view
# apiview
# viewsets
# GenericAPIView

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:
            course_list = Course.objects.all()
            ser = CourseSerializers(course_list,many=True)
            ret['data'] = ser.data
        except Exception as e:
            ret['code'] = 1001,
            ret['data'] = '获取课程失败'
        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 = CourseDetail.objects.filter(course_id=pk).first()
            ser = CourseDetailSerializers(instance=obj,many=False)
            ret['data'] = ser.data
        except Exception as e:
            ret['code'] = 1001,
            ret['data'] = '获取课程失败'
        return Response(ret)

 

serializers/course.py

from rest_framework import serializers
from api import models

class CourseSerializers(serializers.ModelSerializer):
    """
    课程序列化
    """
    level = serializers.CharField(source='get_level_display')
    class Meta:
        model = models.Course
        fields = ['id','title','course_img','level']


# class CourseDetailSerializers(serializers.ModelSerializer):
#     class Meta:
#         model = models.CourseDetail
#         fields = "__all__"
#         depth = 1   # 这个可以实现 关联的表 都拿到数据  不介意这么做!!
#

class CourseDetailSerializers(serializers.ModelSerializer):
    """
    课程详细序列化
    """
    # source 处理             one2one / 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
    # recommend_courses = serializers.CharField(source='recommend_courses.all')  # 这种方式不会序列化 不用这种

    # SerializerMethodField  处理 m2m
    recommends = serializers.SerializerMethodField()

    # 所有章节
    chapters = serializers.SerializerMethodField()

    class Meta:
        model = models.CourseDetail
        fields = ["course","title","img","level","slogon","why","recommends","chapters"]

    def get_recommends(self, obj):
        # 获取推荐的所有课程
        queryset = obj.recommend_courses.all()
        # 列表生成式
        return [{"id":row.id,"title":row.title} for row in queryset]

    def get_chapters(self, obj):
        # queryset = models.Chapter.objects.filter(course=obj.course).all()  # 正向查询
        queryset = obj.course.chapter_set.all()  # 反向查询
        
        return [{"id":row.id,"num":row.num,"name":row.name} for row in queryset]

 

5. 后端 - as_view() 传参,视图继承ViewSetMixin

url(r'^course/$', course.CourseView.as_view({"get": 'list'})),
url(r'^course/(?P<pk>\d+)/$', course.CourseView.as_view({"get": "retrieve"})),
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:
            course_list = Course.objects.all()
            ser = CourseSerializers(course_list,many=True)
            ret['data'] = ser.data
        except Exception as e:
            ret['code'] = 1001,
            ret['data'] = '获取课程失败'
        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 = CourseDetail.objects.filter(course_id=pk).first()
            ser = CourseDetailSerializers(instance=obj,many=False)
            ret['data'] = ser.data
        except Exception as e:
            ret['code'] = 1001,
            ret['data'] = '获取课程失败'
        return Response(ret)

 

6. 后端 - modes choices 展示显示中文

class Course(models.Model):
    """
    课程表
    """
    title = models.CharField(verbose_name="课程名称", max_length=32)
    course_img = models.CharField(verbose_name='课程图片', max_length=64)
    level_choices = (
        (1, '初级'),
        (2, '中级'),
        (3, '高级')
    )
    level = models.IntegerField(verbose_name="课程难易程度", choices=level_choices,default=1)

    def __str__(self):
        return self.title
class CourseSerializers(serializers.ModelSerializer):
    """
    课程序列化
    """
    level = serializers.CharField(source='get_level_display')
    class Meta:
        model = models.Course
        fields = ['id','title','course_img','level']

 

7. 后端 - 序列化展示 一对一,一对多,多对多 相关内容depth/source/SerializerMethodField

depth = 1 / 2 ... 不介意 ,1层 / 2层 不想要得数据也能拿到

class CourseDetailSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.CourseDetail
        fields = "__all__"
        depth = 1   # 这个可以实现 关联的表 都拿到数据  不介意这么做!!

一对多 / 一对一:

  source 

多对多:

chapters = serializers.SerializerMethodField()
def get_chapters(self, obj):
# queryset = models.Chapter.objects.filter(course=obj.course).all() # 正向查询
queryset = obj.course.chapter_set.all() # 反向查询

return [{"id":row.id,"num":row.num,"name":row.name} for row in queryset]
class CourseDetailSerializers(serializers.ModelSerializer):
    """
    课程详细序列化
    """
    # source 处理             one2one / 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
    # recommend_courses = serializers.CharField(source='recommend_courses.all')  # 这种方式不会序列化 不用这种

    # SerializerMethodField  处理 m2m
    recommends = serializers.SerializerMethodField()

    # 所有章节
    chapters = serializers.SerializerMethodField()

    class Meta:
        model = models.CourseDetail
        fields = ["course","title","img","level","slogon","why","recommends","chapters"]

    def get_recommends(self, obj):
        # 获取推荐的所有课程
        queryset = obj.recommend_courses.all()
        # 列表生成式
        return [{"id":row.id,"title":row.title} for row in queryset]

    def get_chapters(self, obj):
        # queryset = models.Chapter.objects.filter(course=obj.course).all()  # 正向查询
        queryset = obj.course.chapter_set.all()  # 反向查询
        
        return [{"id":row.id,"num":row.num,"name":row.name} for row in queryset]
posted @ 2018-07-17 21:44  Alice的小屋  阅读(563)  评论(0编辑  收藏  举报