路飛學成項目先後端分離/API接口

路飛學城項目以前後端分離

先後端故名思議就是前端和後端分離開來,一我的寫前端,一我的寫後端.前端

先後端都是要基於restful協議進行的vue

後端主要是寫接口,所謂的接口就是url,前端用ajax技術發送請求給後端,向後端拿想要的數據python

然後端只須要返回json數據便可.webpack

用Django的restframework框架寫API接口ios

後端部分web

表結構ajax

 1 from django.db import models
 2 
 3 class Course(models.Model):
 4     """
 5     課程表
 6     """
 7     title = models.CharField(verbose_name='課程名稱',max_length=32)
 8     course_img = models.CharField(verbose_name='課程圖片',max_length=64)
 9     level_choices = (
10         (1,'初級'),
11         (2,'中級'),
12         (3,'高級'),
13     )
14     level = models.IntegerField(verbose_name='課程難易程度',choices=level_choices,default=1)
15 
16     def __str__(self):
17         return self.title
18 
19 class CourseDetail(models.Model):
20     """
21     課程詳細
22     """
23     course = models.OneToOneField(to='Course')
24     slogon = models.CharField(verbose_name='口號',max_length=255)
25     why = models.CharField(verbose_name='爲何要學?',max_length=255)
26     recommend_courses = models.ManyToManyField(verbose_name='推薦課程',to='Course',related_name='rc')
27 
28     def __str__(self):
29         return "課程詳細:"+self.course.title
30 
31 class Chapter(models.Model):
32     """
33     章節
34     """
35     num =  models.IntegerField(verbose_name='章節')
36     name = models.CharField(verbose_name='章節名稱',max_length=32)
37     course = models.ForeignKey(verbose_name='所屬課程',to='Course')
38 
39     def __str__(self):
40         return self.name
modles.py表結構

裏面涉及了多對多,一對多,還有choice字段,基本涵蓋了大多數字段的類型vue-router

url.pynpm

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/(?P<version>\w+)/', include('api.urls')),
]
主url.py
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'})),

]
分發的url

獲取全部的課程表

class CourseView(ViewSetMixin,APIView):

    def list(self,request,*args,**kwargs):
        """
        課程列表接口
        :param request:
        :param args:
        :param kwargs:
        :return:
        """
        ret = {'code':1000,'data':None}

        try:
            queryset = models.Course.objects.all()
            ser = CourseSerializer(instance=queryset,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:
            # 課程ID=2
            pk = kwargs.get('pk')

            # 課程詳細對象
            obj = models.CourseDetail.objects.filter(course_id=pk).first()

            ser = CourseDetailSerializer(instance=obj,many=False)

            ret['data'] = ser.data

        except Exception as e:
            ret['code'] = 1001
            ret['error'] = '獲取課程失敗'

        return Response(ret)
views.py獲取課程與課程詳細

跨域請求處理django

class MiddlewareMixin(object):
    def __init__(self, get_response=None):
        self.get_response = get_response
        super(MiddlewareMixin, self).__init__()

    def __call__(self, request):
        response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request)
        if not response:
            response = self.get_response(request)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response

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
cors.py

settings.py中註冊

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'api.cors.CORSMiddleware',
]
註冊cors.py

序列化組建的使用

from api import models

from rest_framework import serializers

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


class CourseDetailSerializer(serializers.ModelSerializer):
    """
    課程詳細序列化
    """
    # one2one/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','img','level','slogon','why','recommends','chapter']


    def get_recommends(self,obj):
        # 獲取推薦的全部課程
        queryset = obj.recommend_courses.all()

        return [{'id':row.id,'title':row.title} for row in queryset]

    def get_chapter(self,obj):
        # 獲取推薦的全部課程
        queryset = obj.course.chapter_set.all()

        return [{'id':row.id,'name':row.name} for row in queryset]
serializers

自定義字段須要寫在fields裏

get_level_display是取choice的中文名稱

 

fk、onetoone、choice能夠經過source來作

關於多對多和一對多的反向查詢

 # m2m
    recommends = serializers.SerializerMethodField()
    chapter = serializers.SerializerMethodField()


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


    def get_recommends(self,obj):  #多對多
        # 獲取推薦的全部課程
        queryset = obj.recommend_courses.all()

        return [{'id':row.id,'title':row.title} for row in queryset]

    def get_chapter(self,obj):  #一對多的反向查詢
        # 獲取推薦的全部課程 
        queryset = obj.course.chapter_set.all()

        return [{'id':row.id,'name':row.name} for row in queryset]
對多對,一對多,反向查詢的序列化

    對於正向查詢的外鍵:

     title=serializers.CharField(source='course.title')咱們只須要用序列化cource字段就能夠進行跨表獲取數據

    對於多對多字段::

    recommend_course=serializers.SerializerMethodField()首先須要實例化serializers.SerializerMethodField()類

     def get_recommend_course(self, obj): #get_對象名(recommend_course)

     queryset=obj.recommend_course.all() return [{'title':row.title,'level':row.get_level_display()} for row in queryset]

      只要return回想要的數據便可.這裏的obj是view傳遞的obj

  *對於反向查詢的一對多字段:

    chapter=serializers.SerializerMethodField()

   def get_chapter(self,obj):
        queryset=obj.course.chapter_set.all()
        return [{'num':obj.number_chapter,'chater':obj.title} for obj in queryset]    與上述的思路同樣,這裏不作贅述
View Code

前端數據的接收

目錄結構

main.js

// 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=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

index.js

import Vue from 'vue'
import Router from 'vue-router'
// import HelloWorld from '@/components/HelloWorld'
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'
})
index.js

course.vue

<template>
  <div>
    <h1>課程列表</h1>
    <!--<ul v-for="row in courseList">-->
      <!--&lt;!&ndash;<li><router-link to="/detail">{{row.title}}</router-link></li>&ndash;&gt;-->
      <!--<li><router-link :to="{name:'detail',params:{id:row.id}}">{{row.title}}</router-link></li>-->
    <!--</ul>-->
    <div v-for="row in courseList">
      <div style="width: 350px;float: left">
        <!--<img v-bind:src="row.course_img"/>-->
        <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: "index",
    data() {
      return {
        courseList:[

        ]
      }
    },
    mounted:function () {
      // vue頁面剛加載時自動執行
      this.initCourse()
    },
    methods:{
      initCourse:function () {
        /*
        this.courseList = [
          {id:1,title:'Python全棧'},
          {id:2,title:'Linux運維'},
          {id:3,title:'金融分析'},
        ]
        */


        // 經過ajax向接口發送請求,並獲取課程列表
        // axios 發送ajax請求
        // npm install axios --save
        // 第一步:在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) {
          // ajax請求失敗以後,獲取響應的內容
        })

      }
    }
  }
</script>

<style scoped>

</style>
course.vue

detail.vue

<template>
  <div>
    <h1>課程詳細頁面</h1>
    <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.chapter">
          <li>{{item.name}}</li>
        </ul>
      </div>

      <div>
        <ul v-for="item in detail.recommends">
          <li>{{item.title}}</li>
        </ul>
      </div>

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

<script>
  export default {
    name: "index",
    data() {
      return {
        detail:{
          course:null,
          img:null,
          level:null,
          slogon:null,
          title:null,
          why:null,
          chapter:[],
          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){
            that.detail = arg.data.data
          }else{
            alert(arg.data.error)
          }
        })
      }
    }
  }
</script>

<style scoped>

</style>
detail.vue

補充ORM跨表

FK
反向查詢,表名小寫+_set.all()

能夠用反向字段

OnetoOne字段
反向查詢 代表小寫就能夠進行跨表

相關文章
相關標籤/搜索