首页 > Windows开发 > 详细

路飞学成项目前后端分离/API接口

时间:2019-02-26 10:47:12      阅读:186      评论:0      收藏:0      [点我收藏+]

路飞学城项目之前后端分离

前后端故名思议就是前端和后端分离开来,一个人写前端,一个人写后端.

前后端都是要基于restful协议进行的

后端主要是写接口,所谓的接口就是url,前端用ajax技术发送请求给后端,向后端拿想要的数据

而后端只需要返回json数据即可.

用Django的restframework框架写API接口

后端部分

表结构

技术分享图片
 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字段,基本涵盖了大多数字段的类型

url.py

技术分享图片
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获取课程与课程详细

跨域请求处理

技术分享图片
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字段
反向查询 表明小写就可以进行跨表

 

路飞学成项目前后端分离/API接口

原文:https://www.cnblogs.com/weidaijie/p/10435745.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!