項(xiàng)目需求和項(xiàng)目效果圖:
創(chuàng)新互聯(lián)主要從事網(wǎng)站設(shè)計(jì)制作、做網(wǎng)站、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)薩迦,10多年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):13518219792
提供給用戶一個(gè)查詢表單,用戶輸入需要查詢的手機(jī)號(hào)和日期后,就會(huì)得到相應(yīng)的查詢結(jié)果。
用戶查詢表單
查詢結(jié)果效果圖
為什么要先把項(xiàng)目需求和項(xiàng)目效果圖寫在最開始的位置呢?
原因很簡單,為了節(jié)省讀者不必要的時(shí)間!讀者先看到項(xiàng)目需求和項(xiàng)目效果圖后,應(yīng)該能夠基本了解到本文是否能夠?qū)δ惝a(chǎn)生幫助。因?yàn)楣P者在寫該項(xiàng)目的時(shí)候,在查詢一些資料的時(shí)候,也參考了一部分博客,而搜到的博客文章內(nèi)容真真是良莠不齊。很多情況下,搜索到的標(biāo)題乍一看,好像是自己需要的,但是內(nèi)容長篇大論,需要筆者花費(fèi)時(shí)間閱讀之后,才發(fā)現(xiàn)這根本不是自己需要的;更有甚者,"掛著羊頭賣狗肉",除了標(biāo)題,內(nèi)容亂寫一通,和標(biāo)題根本無半毛錢關(guān)系。(請(qǐng)?jiān)徫彝虏垡环╄b于此,我相信很多的讀者和筆者一樣,在根據(jù)關(guān)鍵詞搜索博客文章時(shí),內(nèi)心之中一定有了實(shí)現(xiàn)功能后的效果圖或者看到最終項(xiàng)目效果圖后就能夠知道是不是自己需要的,再?zèng)Q定要不要花費(fèi)時(shí)間來閱讀。因此,筆者把項(xiàng)目效果圖放在最前面,讀者來到本文之后,看到效果圖就能知道和內(nèi)心之中希望實(shí)現(xiàn)的效果圖是不是一樣的或者類似可以進(jìn)行借鑒的,如果是一樣的或可以進(jìn)行借鑒的,那么筆者很高興幫助到你;如果不是,讀者也不用花費(fèi)時(shí)間通篇閱讀完博客之后,才發(fā)現(xiàn)不是自己需要的文章,也能夠節(jié)省一部分的時(shí)間。
項(xiàng)目整體說明:
1、線上已有運(yùn)行了一段時(shí)間的數(shù)據(jù)表,不是對(duì)通過Django模型新建數(shù)據(jù)表,而是對(duì)已經(jīng)存在的數(shù)據(jù)表進(jìn)行操作
2、數(shù)據(jù)表關(guān)聯(lián)關(guān)系復(fù)雜,希望通過自定義SQL來查詢展示數(shù)據(jù)。即:數(shù)據(jù)表關(guān)聯(lián)關(guān)系不理想,無法滿足一對(duì)一關(guān)聯(lián)、一對(duì)多關(guān)聯(lián)(外鍵)、多對(duì)多關(guān)聯(lián)三種關(guān)聯(lián)關(guān)系之中的任何一種(Django模型只支持這三種關(guān)聯(lián)關(guān)系,而且多對(duì)多關(guān)系需要使用中間表的形式,如果你不太理解這句話,請(qǐng)先自行百度下,多對(duì)多表關(guān)系模型是怎樣設(shè)計(jì)的)
而筆者面臨的需求是:三表關(guān)聯(lián)查詢,有三個(gè)表user、session、message。user表的guest_id和session的guest_id相關(guān)聯(lián),session表的talk_id和message表的talk_id相關(guān)聯(lián),
而且session表的talk_id和message表的talk_id,可能是一對(duì)一關(guān)系,也可能是一對(duì)多關(guān)系,還可能是多對(duì)多關(guān)系,總之不符合Django模型中的關(guān)聯(lián)關(guān)系,如果強(qiáng)行使用,會(huì)發(fā)生想象不到的問題,這樣情況下,只能自行編寫自定義查詢的SQL,而不能使用Django的模型對(duì)象來進(jìn)行查詢
3、環(huán)境:
Django 2.0.13
Linux Centos 6.5
MySQL 5.6
Python 3.4
uWSGI 2.0.17
nginx?1.10.2
Django與Python版本對(duì)應(yīng)關(guān)系(讀者不一定非要和筆者使用的相同版本的環(huán)境,但是一定要使用符合對(duì)應(yīng)關(guān)系版本的軟件,不然會(huì)發(fā)生預(yù)料不到的狀況)
Django version? ? ? ? ?Python versions
1.8? ? ? ? ? ? ? ? ? ? ? ? ? ? ?2.7、3.2、3.3、3.4、3.5
1.9、1.10? ? ? ? ? ? ? ? ? ?2.7、3.4、3.5
1.11? ? ? ? ? ? ? ? ? ? ? ? ? ?2.7、3.4、3.5、3.6
2.0? ? ? ? ? ? ? ? ? ? ? ? ? ? ?3.4、3.5、3.6
2.1? ? ? ? ? ? ? ? ? ? ? ? ? ? ?3.5、3.6、3.7
4、需要的知識(shí)
前端(了解)
Python(掌握)
MySQL(了解)
Linux(了解)
這里根據(jù)的是此表單項(xiàng)目所需知識(shí)所占比例來計(jì)算的,實(shí)際上筆者自己還是一名DBA,哈哈
項(xiàng)目目錄:
第一部分:基礎(chǔ)
1.MVC&MTV模式介紹
2.安裝Django
3.創(chuàng)建Django項(xiàng)目
4.項(xiàng)目文件說明
5.Django數(shù)據(jù)庫連接配置
第二部分:Django前后端交互數(shù)據(jù)處理
1.實(shí)現(xiàn)用戶查詢表單功能
2.實(shí)現(xiàn)url請(qǐng)求數(shù)據(jù)后端處理功能
第三部分:Django+uwsgi+nginx 項(xiàng)目部署
1.WSGI、uwsgi、uWSGI介紹及安裝
2.Django+uWSGI+nginx關(guān)系
3.項(xiàng)目部署
第一部分:
如果讀者這部分已經(jīng)有了足夠的了解,那么可以直接跳過進(jìn)行第二部分的參考
1.MVC&MTV模式介紹
1.軟件設(shè)計(jì)規(guī)范,將業(yè)務(wù)處理邏輯、數(shù)據(jù)查詢處理、界面展示代碼分離
2.MVC對(duì)應(yīng)MTV
Model(模型):是應(yīng)用程序中用于處理應(yīng)用程序數(shù)據(jù)邏輯的部分;通常模型對(duì)象負(fù)責(zé)在數(shù)據(jù)庫中存取數(shù)據(jù);負(fù)責(zé)處理數(shù)據(jù)
View(視圖):是應(yīng)用程序中處理數(shù)據(jù)顯示的部分(對(duì)應(yīng)html文件);通常視圖是依據(jù)模型(Model)數(shù)據(jù)創(chuàng)建的;負(fù)責(zé)界面展示
Controller(控制器):是應(yīng)用程序中處理用戶交互的部分;通??刂破髫?fù)責(zé)從視圖(View)讀取數(shù)據(jù),控制用戶輸入,并向模型發(fā)送數(shù)據(jù);負(fù)責(zé)業(yè)務(wù)邏輯
MVC處理框架:
用戶請(qǐng)求(url),通過Controller發(fā)送給Model,Model處理完數(shù)據(jù)通過Controller發(fā)送給View,View經(jīng)過渲染,返回給用戶
MTV處理框架:
Django相較于MVC多了一個(gè)url分發(fā)器(urls.py),作用是將url請(qǐng)求分發(fā)給不同的view處理,view再調(diào)用相應(yīng)的Model和Template
2.安裝Django
[root@backup ~]# /home/python3/bin/pip3 install Django==2.0.13(當(dāng)然了,網(wǎng)上也有使用Python虛擬環(huán)境的)
...
Successfully installed Django pytz
Cleaning up...
3.創(chuàng)建Django項(xiàng)目
[root@backup ~]# cd /home/python3/ (進(jìn)入到想要?jiǎng)?chuàng)建Django項(xiàng)目的目錄下,執(zhí)行命令后,沒有任何輸出信息,即為成功創(chuàng)建Django項(xiàng)目,這里是:user_form)
[root@backup python3]# ./bin/python3 /home/python3/bin/django-admin.py startproject user_form
4.項(xiàng)目文件說明
[root@backup python3]# tree user_form/
user_form/
├── manage.py??????Django命令行管理工具
├── static? ? ? ? ? ? ? ?自行創(chuàng)建,存放css、js等靜態(tài)文件
├── templatags? ? ? 自行創(chuàng)建,存放自定義的模板過濾器
├── templates? ? ? ?自行創(chuàng)建,存放html文件
└── user_form????????
? ? ├── __init__.py? ??一個(gè)空文件,它告訴Python這個(gè)目錄應(yīng)該被看做一個(gè)Python包
? ? ├── settings.py??項(xiàng)目的配置文件
? ? ├── urls.py? ? ? ? ?url分發(fā)器
? ? └── wsgi.py? ? ? ?全名:Web Server GateWay Interface,Web服務(wù)器網(wǎng)關(guān)接口,是Django項(xiàng)目與WSGI兼容的Web服務(wù)器入口,在部署Django+uwsgi+nginx時(shí)使用
5.Django數(shù)據(jù)庫連接配置
默認(rèn)情況下,Django使用的是sqlite數(shù)據(jù)庫,現(xiàn)在要改為連接遠(yuǎn)程的MySQL數(shù)據(jù)庫(當(dāng)然了,也支持其他數(shù)據(jù)庫)
[root@backup ~]# /home/python3/bin/pip3 install pymysql
1.修改項(xiàng)目目錄下的__init__.py文件
import pymysql? ? #因?yàn)镻ython3使用的數(shù)據(jù)庫連接驅(qū)動(dòng)為pymysql,而__init__是Python的一個(gè)構(gòu)造方法,可以啟到初始化的用途,在導(dǎo)入模塊時(shí)自動(dòng)觸發(fā)
pymysql.install_as_MySQLdb()
2.修改項(xiàng)目目錄下的settings.py文件
DATABASES = {
? ? 'default': {
? ? ? ? 'ENGINE': 'django.db.backends.mysql',
? ? ? ? 'NAME': 'xxx',
? ? ? ? 'USER':'xxxx',
? ? ? ? 'PASSWORD':'xxxx',
? ? ? ? 'HOST':'xxx',
? ? ? ? 'PORT':'3306',
? ? }
}
第二部分:
1.實(shí)現(xiàn)用戶查詢表單功能
1)配置settings.py
第一個(gè)需要調(diào)整的地方是57行(不同Django版本可能會(huì)稍有不同),這是為了讓Django知道到哪里去查找我們的html文件
57? ? ? ? ?'DIRS': [os.path.join(BASE_DIR, 'templates')],
第二個(gè)需要調(diào)整的地方是28行(不同Django版本可能會(huì)稍有不同),這是因?yàn)镈jango默認(rèn)只能通過127.0.0.1訪問,加上這個(gè)可以讓任意地址訪問Django項(xiàng)目,當(dāng)然了,測(cè)試階段如此,后期我們還會(huì)調(diào)整
28 ALLOWED_HOSTS = ['*']
2)配置url分發(fā)器,用來接收用戶的url請(qǐng)求,還記得嗎?(MTV框架)
cat /home/python3/user_form/user_form/urls.py
from django.contrib import admin
from django.urls import path
from . import search
urlpatterns = [
? ? path('admin/', admin.site.urls),
? ? path('user_search/',search.user_search),
]
紅色部分是我們自行配置的,user_search表示用戶請(qǐng)求的部分,而search.user_search表示search模塊中user_search的處理函數(shù),from . import search 表示和urls.py同一級(jí)目錄導(dǎo)入
3)配置用戶請(qǐng)求邏輯處理部分,相當(dāng)于View
cat /home/python3/user_form/user_form/search.py?
#coding: utf-8
from django.http import HttpResponse
from django.shortcuts import render_to_response
def user_search(request):
? ? return render_to_response('user_search.html')
4)配置html模板
cat /home/python3/user_form/templates/user_search.html?
? ?
? ?
? ?
2.實(shí)現(xiàn)url請(qǐng)求數(shù)據(jù)后端處理功能
前面雖然實(shí)現(xiàn)了?用戶查詢表單功能 的部分,但是實(shí)際上,現(xiàn)在很多的網(wǎng)站都是動(dòng)態(tài)網(wǎng)站,是需要和后端數(shù)據(jù)庫進(jìn)行交互的,所以,這部分筆者來實(shí)現(xiàn)這部分的需求
1)處理前端html傳輸過來的數(shù)據(jù)部分
cat?/home/python3/user_form/user_form/search.py?
#coding: utf-8
from django.http import HttpResponse
from django.shortcuts import render_to_response
import pymysql
#用戶查詢表單提交數(shù)據(jù)部分
def user_search(request):
? ? return render_to_response('user_search.html')
#將表單數(shù)據(jù)進(jìn)行后端處理的部分
def search4(request):
? ? try:
? ? ? ? request.encoding = 'utf-8'
? ? ? ? if request.GET['q'] is '' or request.GET['startTime'] is '':
? ? ? ? ? ? return HttpResponse('您是否忘記了輸入查詢手機(jī)號(hào)或者查詢?nèi)掌冢?)
? ? ? ? else:
? ? ? ? ? ? names = request.GET['q'].strip()
? ? ? ? ? ? startTime = request.GET['startTime'].strip()
? ? ? ? ? ? db = pymysql.connect(host='xxx', user='xxx', passwd='xxx', db='xxx', charset='utf8')
? ? ? ? ? ? cursor = db.cursor()
? ? ? ? ? ? sql = 'SELECT a.guest_name,a.mobile,a.weixin,a.qq,a.email,b.se,b.kw,b.referer,b.land_page,' \
? ? ? ? ? ? 'b.guest_area,b.talk_time,b.talk_page,' \
? ? ? ? ? ? 'c.msg_type,c.msg,c.worker_id,c.worker_name ' \
? ? ? ? ? ? 'FROM userInfo%s a INNER JOIN session%s b ON a.guest_id = b.guest_id ' \
? ? ? ? ? ? 'INNER JOIN message%s c ON b.talk_id = c.talk_id WHERE a.guest_name LIKE "%%%s%%"' % (startTime,startTime,startTime,names)
? ? ? ? ? ? cursor.execute(sql)
? ? ? ? ? ? result = cursor.fetchall()
? ? ? ? ? ? if result:
? ? ? ? ? ? ? ? return render_to_response('form.html', {'raw': result})? ? ? ? result會(huì)返回一個(gè)二元數(shù)組
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? return HttpResponse('很抱歉,沒有匹配的查詢結(jié)果,請(qǐng)您檢查輸入的手機(jī)號(hào)是否正確!')
? ?? ??
? ? except Exception as e:
? ? ? ? return HttpResponse(e)
2)渲染從后端返回的處理數(shù)據(jù)(俗稱:套模板)
cat /home/python3/user_form/templates/form.html
渲染內(nèi)容較多,筆者只選擇其中重要的部分進(jìn)行講解
{% load staticfiles %}? ? #引用靜態(tài)文件,在后面我會(huì)說明它的用途
{% load msg_type %}? ? #引用自定義過濾器,在后面我會(huì)說明它的用途
?
? xxx
?
? ? ? #引用靜態(tài)文件,settings.py文件中需要配置
? xxx
? ? ? ? ?xxx
? ? ? ? ?
? ? ? ? ?
? ? ? ? ? ?
? ? ? ? ? ?
? ? ? ? ? ? ? ? ? #{{Python引用變量的模板語法,這里為取值第一個(gè)元祖下標(biāo)為10的元素,并交由日期過濾器處理,還記得raw返回的是一個(gè)二維元祖嗎?}}
? ? ? ? ? ?
? ? ? ? ?
? ? ? ? ?
? ? ? ? ? ?
? ? ? ? ? ?
? ? ? ? ? ? ?
? ? ? ? ? ?
? ? ? ?xxx? ? ? ? ?
以上就是最為核心的處理部分,筆者在這里列出一些常見的問題和額外的數(shù)據(jù)處理(比如過濾器的二次處理),希望對(duì)你有所幫助
1.如果你的頁面出現(xiàn)了如下的問題,而不是筆者在博客開始時(shí)展現(xiàn)的效果圖,那么,毫無疑問,你的樣式引用失敗了
解決方法也很簡單,請(qǐng)自行在settings.py文件中的末尾位置,配置你的靜態(tài)文件所在的目錄(筆者的是static,還記得嗎?)
cat /home/python3/user_form/user_form/settings.py?
STATICFILES_DIRS = (
? ? os.path.join(BASE_DIR, "static"),
)
STATIC_URL = '/static/'
2.格式化時(shí)間戳的問題。如圖所示,我希望查詢出來的數(shù)據(jù)直接顯示成?2019-06-20 14:06:27 格式,而不是時(shí)間戳的形式,這樣來說,對(duì)用戶更加的友好不是。類似這種將查詢返回的數(shù)據(jù)進(jìn)行二次處理的函數(shù),被稱為過濾器。類似這樣的需求還有很多,筆者只講這一個(gè)做個(gè)示例
首先是過濾器的settings.py的配置,在大概66行的地方,填寫如下配置,必須和你返回渲染模板引用的過濾器名稱相同。如:form.html開頭引用的?{% load msg_type%},還記得吧?
54 TEMPLATES = [
?55? ? ?{? ?
? ? ? ? ? ? ? ?xxx
?66? ? ? ? ?'libraries':{
?67? ? ? ? ? ? ? ? ?'msg_type':'templatetags.msg_type',
?68? ? ? ? ? ? ?},
其次是自定義Django過濾器,并將其注冊(cè)到Django過濾器中,然后就可以在返回渲染模板中使用該過濾器了。如:form.html開頭引用的
{% load msg_type %}? ?引用自定義過濾器
{{ raw.0.10|riqi }}? ? 使用自定義過濾器
cat /home/python3/user_form/templatetags/msg_type.py
@register.filter
def riqi(shijian):
? ? shijian = int(shijian)
? ? return time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(shijian))
第三部分:
1.WSGI、uwsgi、uWSGI介紹及安裝
2.Django+uWSGI+nginx關(guān)系
3.項(xiàng)目部署
1.WSGI、uwsgi、uWSGI介紹及安裝
WSGI,全名:Web Server Gateway Interface(Web服務(wù)器網(wǎng)關(guān)接口)。簡單來說,WSGI相當(dāng)于一個(gè)管道,一邊連著Web服務(wù)器(如:nginx),另一邊連著用戶的應(yīng)用(如:Django)。通過此管道,協(xié)議之間可以進(jìn)行轉(zhuǎn)換。而uWSGI是一個(gè)Web服務(wù)器,它實(shí)現(xiàn)了uwsgi和wsgi兩種協(xié)議。(關(guān)于協(xié)議內(nèi)容,有興趣的讀者請(qǐng)自行百度)
這個(gè)是筆者從網(wǎng)上找到的比較形象的一張示意圖,以作參考:
安裝uwsgi:
/usr/local/python3/bin/pip3 install uwsgi==2.0.17?
2.Django+uWSGI+nginx關(guān)系
如上圖所示,Server表示nginx、apache等Web服務(wù)器;App表示你的應(yīng)用(如:筆者的Django項(xiàng)目);通過WSGI可以將應(yīng)用和Web服務(wù)器結(jié)合起來,只讓uWSGI處理動(dòng)態(tài)請(qǐng)求,而靜態(tài)請(qǐng)求讓nginx處理即可,畢竟nginx非常擅長靜態(tài)內(nèi)容的處理
3.項(xiàng)目部署
創(chuàng)建uwsgi配置文件
pwd
/home/python3/user_form
cat uwsgi.ini?
[uwsgi]
socket=127.0.0.1:8088? ? 配置這個(gè),只能和nginx結(jié)合使用,而且需要和nginx的配置地址相同,讓nginx反代8088的地址,這也是本文的目的,Django + uWSGI + nginx 項(xiàng)目
#http=192.168.32.3:8088? ? ? 配置這個(gè),啟動(dòng)uWSGI服務(wù),可以直接使用 http://192.168.32.3:8088? 地址進(jìn)行訪問,因?yàn)閡WSGI本身也是一個(gè)Web服務(wù)器
chdir=/home/python3/user_form? ? ?Django項(xiàng)目路徑
wsgi-file=user_form/wsgi.py? ? ?顧名思義,wsgi file
processes=4? ?maximum number of worker processes
threads=2? ? ??
master=true??
pidfile=uwsgi.pid
daemonize=uwsgi.log
vacuum = true? ??clear environment on exit
配置nginx
cat /usr/local/nginx/conf/nginx.conf? ?(每個(gè)人的nginx路徑都不一樣,別照搬;而且筆者假設(shè)你已經(jīng)安裝了nginx;綠色的是和uWSGI相關(guān)的配置信息)
xxx
error_log? /usr/local/nginx/logs/error.log;
events {
? ? worker_connections? 1024;
}
http {
? ? include? ? ? ?mime.types;
? ? default_type? application/octet-stream;
? ? #log_format? main? '$remote_addr - $remote_user [$time_local] "$request" '
? ? #? ? ? ? ? ? ? ? ? '$status $body_bytes_sent "$http_referer" '
? ? #? ? ? ? ? ? ? ? ? '"$http_user_agent" "$http_x_forwarded_for"';
? ? access_log? /usr/local/nginx/logs/access.log;?
? ? sendfile? ? ? ? on;
? ? #tcp_nopush? ? ?on;
? ? #keepalive_timeout? 0;
? ? keepalive_timeout? 65;
? ? #gzip? on;
? ? upstream django {
server 127.0.0.1:8088;? ? ?需要和uwsgi.ini 文件中配置的相同
? ? }
? ? server {
? ? ? ? listen? ? ? ?80;
? ? ? ? server_name? lzb1.com;
root /usr/local/python3/project/user_form;? ? ? ?Django項(xiàng)目路徑
location / {
? ? ? ? ? ? include uwsgi_params;? ? ? 這里的uwsgi_params是從?/usr/local/nginx/conf/? 路徑下拷貝到Django項(xiàng)目路徑下的,用途是?用于nginx 和 uwsgi 之間的請(qǐng)求格式的轉(zhuǎn)換
? ? ? ? ? ? uwsgi_pass django;
? ? ? ? }
location /static {
? ? ? alias /usr/local/python3/project/user_form/static/;? ? ? ? static靜態(tài)文件路徑,畢竟靜態(tài)文件完全可以經(jīng)由nginx來處理,而不必經(jīng)過uWSGI
}
? ? }
}
啟動(dòng)/關(guān)閉uWSGI、nginx
pwd
/home/python3/user_form
/usr/local/python3/bin/uwsgi? --ini uwsgi.ini? 啟動(dòng)
/usr/local/python3/bin/uwsgi --stop uwsgi.pid? ?關(guān)閉
/usr/local/nginx/sbin/nginx -t? 語法檢查
/usr/local/nginx/sbin/nginx? ? ? 啟動(dòng)
/usr/local/nginx/sbin/nginx -s stop? 關(guān)閉
netstat -ntlp | grep 80
tcp? ? ? ? 0? ? ? 0 0.0.0.0:80? ? ? ? ? ? ? ? ? 0.0.0.0:*? ? ? ? ? ? ? ? ? ?LISTEN? ? ? 1425/nginx? ? ? ? ??
tcp? ? ? ? 0? ? ? 0 127.0.0.1:8088? ? ? ? ? ? ? 0.0.0.0:*? ? ? ? ? ? ? ? ? ?LISTEN? ? ? 1413/uwsgi?
配置Windows hosts文件
192.168.32.3 lzb1.com
訪問:
http://lzb1.com/user_search/
至此,Django + uWSGI+ nginx 用戶表單查詢項(xiàng)目,從簡單的MVC&MTV模式介紹、Django安裝,到實(shí)現(xiàn)用戶查詢表單功能、url請(qǐng)求數(shù)據(jù)后端處理功能,再到最后的將項(xiàng)目部署到linux,使其成為一個(gè)成型的項(xiàng)目,已經(jīng)全部完成。
題外:
因?yàn)檫@是筆者第一次使用Python寫成的可以上線使用的項(xiàng)目,文章中難免可能會(huì)有一些理解不到位的地方,請(qǐng)觀看的讀者在下方留言指正!同時(shí),俗語講:"萬事開頭難",對(duì)于第一次獨(dú)立寫成的項(xiàng)目,除了喜悅感和成就感溢于言表之外;寫項(xiàng)目過程之中的困難和彎路,也著實(shí)令人苦惱;寫作本文,一方面記錄筆者自己的成長過程和項(xiàng)目成果,另一方面,也為那些正在苦惱類似表單項(xiàng)目怎么寫,或者將來也要寫類似項(xiàng)目的讀者提供一個(gè)思路,使其少走一些彎路,希望可以幫到你