先後端分離 項目(一)

1. 後端Django項目

目錄結構:html

(1)settings.py文件

# 下載 處理跨域問題的app:
pip install django-cors-headers
# 註冊app:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'api.apps.ApiConfig',
    'corsheaders'  # 註冊app
]
# 註冊中間件:

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware', # 必須放在第一個位置
    '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',
]
# corsheaders配置項:
CORS_ORIGIN_ALLOW_ALL = True  # 容許全部人 跨域請求 個人服務端

(2)api/models.py文件

項目表結構設計前端

  • 課程相關
    • 課程類表CourseCategory
    • 專題課程表Course
    • 課程詳情表CourseDetail
    • 老師表Teacher
    • 價格與有課程效期表PricePolicy
    • 課程章節表CourseChapter
    • 課時目錄表CourseSection
    • 常見問題表OftenAskedQuestion
  • 優惠券相關
    • 優惠券生成規則Coupon
    • 優惠券發放、消費紀錄CouponRecord
  • 訂單相關
    • 訂單Order
    • 訂單詳情OrderDetail
  • 用戶相關
    • 用戶表UserInfo -- 繼承AbstractUser
    • Token

注意:settings.py文件中添加配置項vue

# 告訴Django用我本身寫的 UserInfo表 代替內置的 User表
AUTH_USER_MODEL = 'api.UserInfo'    # app名.表名

(3)api/admin.py文件

from django.contrib import admin
from api import models

admin.site.register(models.Course)          # 課程表
admin.site.register(models.CourseDetail)    # 課程詳情表
admin.site.register(models.CourseCategory)  # 課程分類表
admin.site.register(models.CourseChapter)   # 課程章節表
  • 建立超級用戶
python manage.py createsuperuser
  • 啓動Django項目, 進入admin頁面, 對以上四個表的數據進行修改

(4)urls.py文件

路由分發:java

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

urlpatterns = [
    url(r'^api/', include('api.urls')),
]

(5)api/urls.py文件

路由匹配:python

from django.conf.urls import url
from api.views import course as course_view
from api.views import login as login_view

urlpatterns = [
    # 課程展現
    url(r'courses/$', course_view.CourseListView.as_view()),
]

(6)api/views/course.py文件

from rest_framework.generics import ListAPIView
from api import models
from api.serializers.course import CourseModelSerializer
from rest_framework.response import Response

class CourseListView(ListAPIView):
    queryset = models.Course.objects.all()
    serializer_class = CourseModelSerializer
    
    def get(self, request, *args, **kwargs):
        """"重寫ListAPIView的get方法"""
        pass

因爲是先後端分離, 對於視圖函數CourseListView, 咱們要返回一個合適的接口, 所以,ios

必須重寫父類的get方法. 這個時候, 就須要看一看ListAPIView的源碼了.django

  • ListAPIView源碼:

  • 點擊進入list方法:

如今, 咱們迴歸到原本的問題上, 咱們要重寫ListAPIView的get方法, 從而返回一個合適的接口, 可是, 因爲ListAPIView自己也有一些功能, 若是咱們直接重寫, 勢必會對其餘功能形成影響. 咱們的解決辦法是: 將list方法功能相關的代碼直接粘貼到咱們重寫的get方法裏, 而後在不改動這些代碼的前提下, 進行咱們本身的處理(主要是處理返回值, 即接口).axios

course.py文件:後端

from rest_framework.generics import ListAPIView
from api import models
from api.serializers.course import CourseModelSerializer
from rest_framework.response import Response

class CourseListView(ListAPIView):
    queryset = models.Course.objects.all()
    serializer_class = CourseModelSerializer
    
    def get(self, request, *args, **kwargs):
        try:
            #### list源碼 ####
            queryset = self.filter_queryset(self.get_queryset())
            page = self.paginate_queryset(queryset)
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return self.get_paginated_response(serializer.data)
            serializer = self.get_serializer(queryset, many=True)
            #### list源碼 ####
            data = serializer.data
        except Exception as e:
            code = 1
            msg = str(e)
        res = {'code': code, 'data': data, 'msg': msg}
        return Response(res)

上面代碼中, res這個字典就是咱們與前端交互的接口. 因爲每次都要本身硬編碼該字典內部的key和value, 這樣的作法是不可靠且極爲繁瑣的, 所以, 咱們考慮將它們封裝爲一個對象. 以下所示:

  • 工具類: utils/response.py文件
class BaseResponse(object):

    def __init__(self):
        self.code = 1000  # 狀態碼
        self.data = None  # 具體數據
        self.msg = ''     # 提示信息

    @property
    def dict(self):
        return self.__dict__  # __dict__把類的屬性以字典的形式返回

course.py文件: 改進版本

from rest_framework.generics import ListAPIView
from api import models
from api.serializers.course import CourseModelSerializer
from rest_framework.response import Response
from utils.response import BaseResponse # 引入自定義工具類

class CourseListView(ListAPIView):
    queryset = models.Course.objects.all()
    serializer_class = CourseModelSerializer
    
    def get(self, request, *args, **kwargs):
        res_obj = BaseResponse()    # 實例化自定義工具類
        try:
            #### list源碼 ####
            queryset = self.filter_queryset(self.get_queryset())
            page = self.paginate_queryset(queryset)
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return self.get_paginated_response(serializer.data)
            serializer = self.get_serializer(queryset, many=True)
            #### list源碼 ####
            res_obj.data = serializer.data  # 賦值給data屬性
        except Exception as e:
            res_obj.code = 1          # 賦值給code屬性
            res_obj.msg = str(e)      # 賦值給msg屬性
        return Response(res_obj.dict) # 經過dict方法就能夠拿到全部屬性組成的字典

(7)api/serializers/course.py文件

自定義序列化類CourseModelSerializer:

from rest_framework import serializers
from api import models

class CourseModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Course
        fields = "__all__"

2. 前端Vue項目

(1)src/main.js文件

配置根URL:

// 導入Axios
import Axios from 'axios'
Axios.defaults.baseURL = 'http://127.0.0.1:8001/api';
Vue.prototype.$axios = Axios;

(2)src/router.js文件

路由匹配:

import Course from './views/Course.vue'

Vue.use(Router);
export default new Router({
    routes: [
                {
            path: '/course',
            name: 'course',
            component: Course,
        },
    ]
})

(3)src/views/Course.vue文件

自定義組件Course.vue:

getCourseList() {
    this.$axios.get('/courses/')    // 修改路徑,要與後端的路徑信息相匹配
        .then((res) => {            // res 是接收到的後段的返回值
            // console.log(res);
            if (res.data.code === 1000) {   // code狀態碼
                this.courseList = res.data.data;    // data具體數據信息
                // 去掉加載動畫
                this.loading = false
            }
        })
},
相關文章
相關標籤/搜索