Djnaog 之路飞学城前后端分离/api接口

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

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

前后端都是要基于restful协议进行的.那么什么是resful协议?

 

restful协议

 

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

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

用Django的restframework框架写API接口

 

提供简单的model

model

class Course(models.Model):
    '''课程表'''
    Course_level=(
        (0,'低级'),
        (1,'中级'),
        (2,'高级'),
    )
    title=models.CharField(max_length=32,verbose_name='课程')
    img_src=models.CharField(max_length=64,default='static/images/logo.png')
    level=models.PositiveIntegerField(choices=Course_level,default=1)


    def __str__(self):
        return  self.title


class CourseDetail(models.Model):
    '''课程详细表'''
    name=models.CharField(max_length=255,verbose_name='口号')
    course=models.OneToOneField('Course',on_delete=models.CASCADE,related_name='c')
    why_study=models.TextField(verbose_name='为什么学习')
    recommend_course=models.ManyToManyField('Course',related_name='course_recomend',verbose_name='推荐课程',null=True,blank=True)

    def __str__(self):
        return self.name

class Chapter(models.Model):
    '''章节'''
    number_chapter=models.IntegerField(verbose_name='第几章节')
    title=models.CharField(max_length=32,verbose_name='章节名称')
    chapter_course=models.ForeignKey('Course',on_delete=models.CASCADE)

    def __str__(self):
        return '第%s章节%s'%(self.number_chapter,self.title)

里面涉及了多对多,一对多,还有choice字段,基本涵盖了大多数字段的类型

 

url:

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path(r'^api/(?P<version>\w+)/', include('api.urls')),
]
urlpatterns = [
    path('course/',course.CourseView.as_view({'get':'list'})),
    re_path(r'^course/(?P<pk>\d+)/$',course.CourseView.as_view({'get':'retrieve',
                                                                'put':'update',
                                                                'delete':'destroy'})),

]

 

获取所有的课程表

view:

class CourseView(ViewSetMixin,APIView):
    def list(self,request,*args,**kwargs):
        '''查看课程列表'''
        ret={'code':1000,'data':None}
        try:
            queryset=models.Course.objects.all()
            ser=apiserializer.CourseModelSerializer(instance=queryset,many=True)
            ret['data']=ser.data
        except Exception as e:
            ret['code']=1001
            ret['data']='获取数据错误'
        return Response(ret)

再来看序列化组件:

class CourseModelSerializer(ModelSerializer):
    '''Course表的序列化'''
    level=serializers.CharField(source='get_level_display')
    class Meta:
        model=models.Course
        fields=['id','title','img_src','level']
    # 不建议用,因为有太多的无用信息
     #depth=1 #0-10

 

自定义字段需要写在fields里

get_level_display是取choice的中文名称

自定义字段后面会详细说明

 

前端vue接收数据:

main.js:

import axios from 'axios'
import Vuex from 'vuex'
Vue.use(Vuex);
Vue.prototype.$axios = axios;


const store = new Vuex.Store({
  state: {
      allCourseList:[],
      //这里面的状态跟每个组件的数据属性有关系
  },
  mutations: {
    GETCOURSELIST(state,newValue){
      state.allCourseList =newValue;
    },

  },

  actions:{
    GetCourseList(context,){
      axios.request({
        url:'http://127.0.0.1:8000/api/v2/course/',
        method:'GET',
      }).then(function(ret){
        context.commit('GETCOURSELIST',ret.data.data)
      }).catch(function(ret){
      })
    },
  },

});
main.js

在初始化course组件的时候发送请求接收数据:

Vcourse.vue

mounted(){
      this.$store.dispatch('GetCourseList');
}
View Code

在VcourseList.vue里获取到state里的数据然后传给子vue

<template>
  <ul>
    <VcourseItem v-for="item in GetAllList" :data="item"></VcourseItem>
  </ul>
</template>

<script>
  import VcourseItem from './VcourseItem'
    export default {
        name: "VcourseList",
        data() {
            return {}
        },
      components:{
          VcourseItem,
      },
      computed:{
        GetAllList(){
          return this.$store.state.allCourseList
        },
      }
    }
</script>

<style scoped>

</style>
View Code

VcourseItem.vue

<template>
  <li>
    <router-link :to="{name:'detail',params:{id:data.id}}">
    <img :src="'/'+data.img_src" alt="">
    <div>{{data.title}}</div>
    </router-link>
    <div>难度{{data.level}}</div>
  </li>
</template>

<script>
    export default {
        name: "VcourseItem",
        data() {
            return {
            }
        },
        props:{
          data:Object,
        },

    }
</script>

<style scoped>

</style>
View Code

 

props

这里需要说明的是,父vue传数据到子vue,进行验证

props:{

data:Object}

props所有的数据类型

props: {
  title: String,
  likes: Number,
  isPublished: Boolean,
  commentIds: Array,
  author: Object
}

可以看到vue里有跳转到查看详细的router-link

    <router-link :to="{name:'detail',params:{id:data.id}}">

{
      path: '/detail/:id',
      name: 'detail',
      component: Vdetail
    },

 

如何序列化有外键的字段

view:

   def retrieve(self,request,*args,**kwargs):
        '''查看课程详细'''
        ret={'code':1000,'data':None}
        try:
            pk=kwargs.get('pk')
            obj=models.CourseDetail.objects.filter(course_id=pk).first()
            ser=apiserializer.CourseDetailModelSerializer(instance=obj)
            ret['data']=ser.data
        except Exception as e:
            ret['code'] = 1001
            ret['error'] = '获取数据错误'

        return Response(ret)

 具体操作

前面介绍了前后端分离的整个过程,那么这里主要介绍对 对多对,一对多,反向查询的序列化

  • 对于正向查询的外键:
     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]    与上述的思路一样,这里不做赘述
 
class CourseDetailModelSerializer(ModelSerializer):
    '''CourseDetail'''
    title=serializers.CharField(source='course.title')
    img=serializers.CharField(source='course.img_src')
    level=serializers.CharField(source='course.get_level_display')
    recommend_course=serializers.SerializerMethodField()
    chapter=serializers.SerializerMethodField()

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

    def get_chapter(self,obj):
        queryset=obj.course.chapter_set.all()
        return [{'num':obj.number_chapter,'chater':obj.title} for obj in queryset]

    class Meta:
        model=models.CourseDetail
        fields=['id','name','why_study','title','img','level','chapter','recommend_course']

 

补充ORM跨表和构建列表:

1.ORM

FK
反向查询,表名小写+_set.all()

可以用反向字段

OnetoOne字段
反向查询 表明小写就可以进行跨表

 

数据结构构建补充:

ret=[{'title':'123','msg':'456'},{'title':'789','msg':'000'},]

new=[{'title':row['title']} for row in ret]

print(new)

[{'title': '123'}, {'title': '789'}]
 

 

posted @ 2018-07-25 17:54  R00M  阅读(362)  评论(0编辑  收藏  举报