娃在幼兒園吃了些啥V2:用Vue.js + Django重寫項(xiàng)目

前情提要

之前出于自身興趣饼问,給娃幼兒園寫了個(gè)每日菜單的網(wǎng)站,并添加到訂閱號(hào)中(V1版簡(jiǎn)書(shū)鏈接)揭斧。主要通過(guò)頁(yè)面上的js與Django后臺(tái)交互莱革,同樣通過(guò)頁(yè)面上的js完成返回?cái)?shù)據(jù)的解析和呈現(xiàn)。
為了更系統(tǒng)地完成前端開(kāi)發(fā)讹开,這次一邊學(xué)習(xí)vue.js框架盅视,一邊利用vue改寫前端,于是就有了菜單網(wǎng)站項(xiàng)目的第二版(github鏈接)旦万。

項(xiàng)目結(jié)構(gòu)

前端改用vue.js構(gòu)建闹击,后端仍然使用django服務(wù),處理前端的數(shù)據(jù)請(qǐng)求成艘,完成數(shù)據(jù)庫(kù)查詢赏半。
整個(gè)項(xiàng)目目錄結(jié)構(gòu)如下:

kinder_foods_vue_django
├─backend
│ ├─__pycache__
│ ├─__init__.py
│ ├─settings.py
│ ├─urls.py
│ └─wsgi.py
├─frontend
│ ├─dist
│ │ ├─static
│ │ │ ├─css
│ │ │ └─js
│ │ └─index.html
│ ├─node_modules
│ ├─public
│ ├─src
│ │ ├─assets
│ │ ├─components
│ │ │ ├─MenuTable.vue
│ │ │ └─SelectDate.vue
│ │ ├─views
│ │ │ ├─ChartView.vue
│ │ │ └─MenuView.vue
│ │ ├─App.vue
│ │ ├─main.js
│ │ └─router.js
│ ├─babel.config.js
│ ├─package.json
│ ├─README.md
│ └─vue.config.js
├─menu
└─manage.py

frontend目錄為vue的項(xiàng)目目錄贺归,其余為Django項(xiàng)目,Django的APP名為menu断箫。

準(zhǔn)備工作

檢查版本

vue -V

C:\Users\ZHANG JIZHONG\Documents\Projects\Python\kinder_foods_vue_django>vue -V
3.8.4

使用VUE UI創(chuàng)建項(xiàng)目

網(wǎng)上用命令行腳手架的教程較多拂酣,這里就偷懶用ui來(lái)創(chuàng)建項(xiàng)目了。

vue ui

C:\Users\ZHANG JIZHONG\Documents\Projects\Python\kinder_foods_vue_django>vue ui
?? Starting GUI...
?? Ready on http://localhost:8000

Vue項(xiàng)目管理器

因?yàn)槎际莡i方式的仲义,每一步截圖會(huì)比較多踱葛,這里選取選擇功能的截圖作為代表,圖中開(kāi)啟了Bable光坝、Router和Linter功能尸诽。


選擇功能

添加bootstrap-vue引用

同樣地,依賴也可以通過(guò)ui方式安裝:


安裝依賴

搜索并安裝bootstrap-vue盯另,并在全局main.js中添加以下內(nèi)容方能使用:

import BootstrapVue from 'bootstrap-vue'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
Vue.use(BootstrapVue)

Vue前端結(jié)構(gòu)

組件

  1. MenuTable.vue

負(fù)責(zé)呈現(xiàn)菜單的組件性含,使用bootstrap-vue中的<b-table>,綁定計(jì)算屬性daily_menu

computed: {
    daily_menu: function () {
        for (let week in this.menu) {
            return this.menu[week];
        }
    }
},

其中鸳惯,menu是MenuTable組件的屬性:

props: ['menu'],

template塊主要內(nèi)容:

<template>
   <b-table responsive="md" bordered :items="daily_menu">
        <template slot="日期" slot-scope="data">
          <strong>{{ data.value.date }}<br/>{{ data.value.weekday }}</strong>
        </template>
        <span slot="早點(diǎn)" slot-scope="data" v-html="data.value"></span>
        <span slot="午餐" slot-scope="data" v-html="data.value"></span>
        <span slot="午點(diǎn)" slot-scope="data" v-html="data.value"></span>
        <span slot="體弱兒營(yíng)養(yǎng)菜" slot-scope="data" v-html="data.value"></span>
      </b-table>
</template>

可見(jiàn)該表格共5列商蕴,日期列分行顯示日期和星期幾,其余列直接提取同名屬性即可芝发,這些屬性都是原生html绪商。
至于為什么要用html,是因?yàn)槊款D餐食的品種數(shù)量是不確定的辅鲸,需要添加換行標(biāo)簽
格郁。
為了方便起見(jiàn),后端返回的數(shù)據(jù)也做了相應(yīng)修改(關(guān)于這點(diǎn)在Django的views部分中具體描述)独悴。

  1. SelectDate.vue

選擇日期的組件例书,依賴于charliekassel/vuejs-datepicker,在本地需先導(dǎo)入

import Datepicker from 'vuejs-datepicker';
import * as lang from "vuejs-datepicker/src/locale";

lang用于本地化刻炒,中文格式設(shè)置如下:

data() {
    return {
        format: "yyyy年MM月dd日",
        language: "zh",
        languages: lang,
    }
},

詳細(xì)的配置可以訪問(wèn)作者的github
template塊的主要內(nèi)容:

<template>
    <div>
        <datepicker placeholder="選擇日期" :language="languages[language]" :format="format" v-on:selected = "sendEvent" >
        </datepicker>
    </div>
</template>

為該組件配置了一個(gè)事件决采,當(dāng)日期被選中時(shí),調(diào)用sendEvent方法坟奥,方法定義:

sendEvent: function(query_date) {
    this.$emit("selected", query_date);
}

該方法將選中的日期作為參數(shù)树瞭,使當(dāng)前組件產(chǎn)生一個(gè)"selected"事件(這個(gè)selected與datepicker的selected同名,但不是同一個(gè)事件爱谁,是SelectDate組件的事件)

  1. MenuView.vue

一個(gè)容納以上兩個(gè)組件的視圖組件晒喷,內(nèi)容不多的情況下也可以省略這是視圖組件,直接把上面?zhèn)z組件放到App.vue里去管行。
template塊的主要內(nèi)容:

<template>
    <div>
        <SelectDate v-on:selected = "get_menu"/>
        <b-alert v-model="failure" variant="danger" dismissible>
        沒(méi)有{{query_date}}的數(shù)據(jù)哦!
        </b-alert>
        <MenuTable v-bind:menu = "menu"/>
    </div>
</template>

監(jiān)聽(tīng)SelectDate組件的selected事件厨埋,捕捉后調(diào)用get_menu方法邪媳。
get_menu方法向后臺(tái)傳遞query_date屬性捐顷,請(qǐng)求menu數(shù)據(jù):

get_menu: function(query_date) {
    let year = query_date.getFullYear();
    let month = query_date.getMonth() + 1;
    let day = query_date.getDate();
    this.query_date = year + '年' + month + '月' + day + '日';
    query_date = year + '-' + month + '-' + day;

    this.$http.post('/ajax/',
        {query_date: query_date},
        {emulateJSON: true}) // 使用form-data才可以荡陷,否則querydict空
    .catch(function(error) { // 處理未得到數(shù)據(jù)的異常
        this.failure = true;
        return Promise.reject(error);
    }).then(function(response){ // 成功返回?cái)?shù)據(jù)
        this.failure = false;
        this.menu = response.data;
    });
}

如果從/ajax/請(qǐng)求中成功獲取后臺(tái)數(shù)據(jù),那么更新this.menu屬性(綁定到了MenuTable的menu屬性)迅涮,達(dá)到更新MenuTable組件中menu這個(gè)prop的目的废赞。
如果未能成功獲取后臺(tái)數(shù)據(jù),那么this.failure為true叮姑,頁(yè)面顯示<b-alert>唉地,提示用戶沒(méi)有這一天的數(shù)據(jù)。

  1. ChartView.vue

這個(gè)組件原本打算進(jìn)行一些可視化的嘗試传透,目前還是空的耘沼,不過(guò)大致想好了放些什么了。既然是跟吃的有關(guān)的網(wǎng)站朱盐,那就放些食物營(yíng)養(yǎng)成分之類的圖表群嗤,類似于foodwake,不知道這方面有沒(méi)有更好的推薦兵琳?

  1. App.vue

這里就相對(duì)簡(jiǎn)單了狂秘,添加兩個(gè)路由鏈接和路由視圖即可。
template塊的主要內(nèi)容:

<template>
    <div id="app">
        <div id="nav">
            <router-link to="/" class="text-white">菜單</router-link>
            <router-link to="/chart" class="text-white">敬請(qǐng)期待</router-link>
        </div>
        <keep-alive>
        <router-view/>
        </keep-alive>
    </div>
</template>

為了使兩個(gè)視圖在切換的時(shí)候不銷毀躯肌,需要在<router-view>標(biāo)簽外添加<keep-alive>者春,這樣選擇的日期和呈現(xiàn)的內(nèi)容不會(huì)因?yàn)榍袚Q視圖而重新初始化。

  1. 修改頁(yè)面標(biāo)題

頁(yè)面的標(biāo)題即網(wǎng)頁(yè)標(biāo)簽上顯示的內(nèi)容清女,在HTML中存在于<head>標(biāo)簽的<title>中钱烟。
在vue.js中需要在路由中添加相關(guān)信息,router.js


routes: [
    {
        path: '/',
        name: 'menu-view',
        component: MenuView,
        meta: {
            title: '幼兒園每周菜譜'
        }
    },
]

其中meta.title就是添加的標(biāo)題信息嫡丙。還要在main.js中增加相應(yīng)處理:

router.beforeEach((to, from, next) => {
    document.title = to.meta.title
    next()
})
  1. 指定靜態(tài)文件目錄

npm打包時(shí)忠售,會(huì)將用到的css和js打包到靜態(tài)目錄中去。默認(rèn)的靜態(tài)目錄未必滿足要求迄沫,可以通過(guò)vue.config.js文件指定:

module.exports = {
    assetsDir : 'static' 
}

這里的assetsDir是基于outputDir的相對(duì)路徑稻扬,所以實(shí)際上是frontend/dist/static。

Django后端

前端全部交給了vue.js羊瘩,因此Django只用跑WEB服務(wù)泰佳,以及處理前端的請(qǐng)求。

views的修改

在MenuTable.vue組件中提到了尘吗,由于每頓餐食的數(shù)量不固定逝她,比如午餐可能是四鮮餛飩和瑪瑙松仁甜飯共兩樣食物,也可能是土豆肋排木耳湯睬捶、花菜炒雙菇黔宛、金玉滿堂和麥片飯共四種。糾結(jié)了一下擒贸,還是用python更為方便臀晃,在食物和食物之間直接拼接了
觉渴。這樣前端直接用原生HTML顯示即可。但是這個(gè)做法徽惋,就在前后端增加了耦合性案淋,而前后端分開(kāi)開(kāi)發(fā)的一個(gè)重要目的就是解耦,所以這方面有點(diǎn)小遺憾险绘。

整合前后端

這里采取的方法是由npm完成打包踢京,將打包后的目錄作為Django的“模板”目錄。
在settings.py中指定模板目錄(frontend/dist)


TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['frontend/dist'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

將前端的靜態(tài)目錄添加到Django的settings中宦棺,以便找到npm打包后的靜態(tài)文件

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "frontend/dist/static"),
]

url中添加對(duì)根路徑的訪問(wèn)瓣距,指向npm生成的index.html

url(r'^$', TemplateView.as_view(template_name='index.html'))

如此整合后,只需運(yùn)行Django服務(wù)代咸,即可完成整個(gè)網(wǎng)站的部署旨涝。

效果預(yù)覽

  • 菜單頁(yè):


    菜單
  • 敬請(qǐng)期待頁(yè):


    敬請(qǐng)期待倒計(jì)時(shí)

小結(jié)

這次主要是學(xué)習(xí)vue.js寫前端的過(guò)程,碰到過(guò)一些諸如頁(yè)面標(biāo)題侣背、靜態(tài)文件輸出路徑等小問(wèn)題白华,都能在網(wǎng)上找到解決方案,總體來(lái)說(shuō)還算比較順利贩耐。
項(xiàng)目主要還是以Django服務(wù)運(yùn)行弧腥,只是用vue代替了原本Django中的templates那一部分。因?yàn)镈jango主要是通過(guò)渲染模板完成前端呈現(xiàn)潮太,對(duì)于前端的開(kāi)發(fā)支持其實(shí)并不充分管搪。而用vue寫前端如果熟練的話效率會(huì)更高。??

參考

整合 Django + Vue.js 框架快速搭建web項(xiàng)目

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末铡买,一起剝皮案震驚了整個(gè)濱河市更鲁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌奇钞,老刑警劉巖澡为,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異景埃,居然都是意外死亡媒至,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門谷徙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拒啰,“玉大人,你說(shuō)我怎么就攤上這事完慧∧钡” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)册着。 經(jīng)常有香客問(wèn)我拴孤,道長(zhǎng),這世上最難降的妖魔是什么指蚜? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮涨椒,結(jié)果婚禮上摊鸡,老公的妹妹穿的比我還像新娘。我一直安慰自己蚕冬,他們只是感情好免猾,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著囤热,像睡著了一般猎提。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上旁蔼,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天锨苏,我揣著相機(jī)與錄音,去河邊找鬼棺聊。 笑死伞租,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的限佩。 我是一名探鬼主播葵诈,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼祟同!你這毒婦竟也來(lái)了作喘?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤晕城,失蹤者是張志新(化名)和其女友劉穎泞坦,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體砖顷,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡暇矫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了择吊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片李根。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖几睛,靈堂內(nèi)的尸體忽然破棺而出房轿,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布囱持,位于F島的核電站夯接,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏纷妆。R本人自食惡果不足惜盔几,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望掩幢。 院中可真熱鬧逊拍,春花似錦、人聲如沸际邻。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)世曾。三九已至缨恒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間轮听,已是汗流浹背骗露。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留血巍,地道東北人椒袍。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像藻茂,于是被迫代替她去往敵國(guó)和親驹暑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348