小試牛刀Flask

在情人節(jié)這天寫技術(shù)文檔泵喘,太沒(méi)有情調(diào)了。不過(guò)有情人的話般妙,哪天不是情人節(jié)纪铺,哈哈。

0x00 背景

在流程不太明確碟渺,每個(gè)人的責(zé)任邊界比較模糊的時(shí)候鲜锚,軟件需求與產(chǎn)品都是個(gè)深坑。

0x001 未必是坑

對(duì)于在這個(gè)工作的經(jīng)辦人而言苫拍,這個(gè)時(shí)候的需求與產(chǎn)品會(huì)是:

  1. 一個(gè)關(guān)鍵的流程梳理工具
  2. 劃分管理責(zé)任的重要依據(jù)
  3. 項(xiàng)目工作流程實(shí)時(shí)可見的重要手段
  4. 問(wèn)題追溯定位的重要來(lái)源

0x002 要求不低

理想很豐滿芜繁,畢竟在一片混沌之中,有個(gè)人殺出一條路之后绒极,此后也就有路了骏令。所以,為了完成這個(gè)目標(biāo)集峦,系統(tǒng)應(yīng)該要具備:

  1. 有一個(gè)可以快速開發(fā)的框架伏社,至少包括數(shù)據(jù)持久化,后臺(tái)處理與前臺(tái)交互
  2. 需要一個(gè)隨需應(yīng)變(On Demand)的設(shè)計(jì)架構(gòu)塔淤,因?yàn)闃I(yè)務(wù)會(huì)隨時(shí)的改摘昌,包括原來(lái)起初為一個(gè)會(huì)議參會(huì)人員設(shè)計(jì)的功能要變成多個(gè)會(huì)議同時(shí)進(jìn)行的功能
  3. 開發(fā)起來(lái)時(shí)間一定要短,效果一定不能太差高蜂,而且必須通過(guò)網(wǎng)絡(luò)訪問(wèn)

嚴(yán)格來(lái)說(shuō)聪黎,上面那些需求都是非功能需求,那功能需求是:

  1. 能夠通過(guò)處理相片的規(guī)則化命名,新建參會(huì)人員的姓名稿饰、單位锦秒、證卡類型、參加會(huì)議的種類
  2. 保留那些命名錯(cuò)誤的照片喉镰,等待手工處理旅择,總有一部分人提交的數(shù)據(jù)每次都有問(wèn)題
  3. 整理完一個(gè)批次的入庫(kù)資料后,會(huì)打包并新建一個(gè)excel表格侣姆,經(jīng)校驗(yàn)完之后生成一個(gè)zip壓縮包生真,同時(shí)將證件的狀態(tài)變成“送打印”
  4. 每次打包的資料都是當(dāng)前證件類型中未打印的資料
  5. 卡證制作完畢后對(duì)每張證件進(jìn)行校驗(yàn),核校數(shù)據(jù)捺宗,通過(guò)點(diǎn)擊“核兄埃”按鈕,將證件狀態(tài)變成“已核醒晾鳎”
  6. 對(duì)成產(chǎn)完成的證卡信息自動(dòng)生成移交文檔长已,通過(guò)選擇批次數(shù)來(lái)選定數(shù)據(jù),并合并同類證卡的人員名單
  7. 會(huì)議結(jié)束后昼牛,整理出每種證件制作的數(shù)量术瓮,并打印名單

在功能需求中提到的工作,就是我實(shí)際工作的內(nèi)容匾嘱,數(shù)據(jù)提交很零散斤斧,要匯總成一個(gè)大表,耗費(fèi)的時(shí)間比較長(zhǎng)霎烙,沒(méi)有一個(gè)確切的統(tǒng)計(jì)數(shù)據(jù)和列表撬讽,核對(duì)制作證卡的時(shí)候就容易出錯(cuò),上面的活不是很難悬垃,就是很反鎖游昼,很容易錯(cuò),而且時(shí)候要做統(tǒng)計(jì)的時(shí)候又要花去不少的時(shí)間尝蠕,此外還可能有多次提交制卡信息的單位烘豌,一個(gè)人實(shí)在是hold不住啊。

事情做久了看彼,自己對(duì)業(yè)務(wù)熟悉了廊佩,別人就不清楚了,所以到頭來(lái)重?fù)?dān)還得自己挑靖榕。所以拿起武器标锄,開干,核心程序?qū)懥巳齻€(gè)晚上茁计,白天在真實(shí)數(shù)據(jù)與環(huán)境下調(diào)試了幾天料皇,主要是那些不按照規(guī)定亂命名的文件名,讓我寫了很多異常處理的語(yǔ)句。

0x01 準(zhǔn)備

我能拿起來(lái)的開發(fā)語(yǔ)言無(wú)非就是asp.net践剂、java鬼譬、php、python逊脯,至于javascript的什么Node.js优质,什么angularJs,什么TypeScript男窟,今年應(yīng)該就沒(méi)問(wèn)題了盆赤。備選的框架有:

  1. asp.net MVC5
  2. java Spring
  3. php thinkPhp
  4. python django/flask

為了保持技術(shù)的連貫性,我選擇python歉眷,框架的選擇是一個(gè)難題,選熟悉的django還是選更流行的flask颤枪,看了一下午的文檔之后最終選擇汗捡,挑戰(zhàn)自己,選擇從未碰過(guò)的flask畏纲。

0x011 配置環(huán)境

0x0111 選擇Anaconda

選擇Anaconda python2.7 的發(fā)行版扇住,下次選擇python3.5的,有windows,mac與linux版本盗胀。

0x0112 選擇pycharm

工欲善其事艘蹋,必先利其器

Python的IDE有很多,當(dāng)然你也可以選擇不用票灰,但是我選的是Pycharm

0x0113

需要安裝的一些插件

pip install flask_bootstrap
pip install flask_moment
pip install docx
pip install pymysql

缺了的套件都可以用 pip install來(lái)安裝

0x02 架構(gòu)

大體來(lái)說(shuō)女阀,代碼架構(gòu)是這樣的

flack/
├── app.py
├── database.py
├── models.py
├── home.py
├── templates/
| └── some template html files
├── static/
| └── client-side js and css files
└── requirements.txt

0x021 大致框架

flask的框架大概是這樣的:

  • app.py的主要內(nèi)容是包括頁(yè)面顯示,后臺(tái)處理屑迂,Ajax服務(wù)以及自定義的頁(yè)面面模版管道
  • database.py與models.py主要是做數(shù)據(jù)持久化浸策,以及數(shù)據(jù)實(shí)體的處理
  • home.py是處理flask部署的時(shí)候設(shè)置

0x022 簡(jiǎn)單的后臺(tái)處理流程

而頁(yè)面處理主要是:

    """
    初始化flask框架
    """
    app = Flask(__name__)
    """
    初始化bootstrap前端樣式
    """
    bootstrap = Bootstrap(app)
    @app.route('/index')
    def index():
    SQLQuery = '''select `user`.type_id,count(*)
              from attend,`user`
              where attend.user_id=`user`.id
                   and attend.`status`=TRUE
                   and attend.meeting_id = %s
              GROUP BY `attend`.cardtype_id'''
    result = db_session.execute(SQLQuery % getMeeting_id())

    return render_template('index.html', result=result)
  1. @app.route('/index') 表示uri,資源的訪問(wèn)路徑
  2. def index(): 定義一個(gè)函數(shù)惹盼,可以與路徑名不一樣庸汗,但是必須唯一,不支持函數(shù)重載
  3. return render_template('index.html', result=result) 啪啦啪啦處理完了之后手报,通過(guò)render_template來(lái)與模版一起渲染蚯舱,通過(guò)ninja引擎,來(lái)實(shí)現(xiàn)展現(xiàn)頁(yè)面

0x023 簡(jiǎn)單的頁(yè)面前端實(shí)現(xiàn)

必須實(shí)現(xiàn)框架的基本模版掩蛤,擴(kuò)展的是bootstrap框架的模版

base.html

    {% extends "bootstrap/base.html" %}

    {% block title %}資料管理系統(tǒng){% endblock %}

    {% block navbar %}
        <div class="navbar navbar-inverse" role="navigation">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                        <span class="sr-only">Toggle navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <a class="navbar-brand" href="/index">參會(huì)人員管理系統(tǒng)</a>
                </div>
                <div class="navbar-collapse collapse">
                    <ul class="nav navbar-nav">
                        <li><a href="/zhengjian/jizhe">記者證</a></li>
                        <li><a href="/zhengjian/lan">藍(lán)色工作證</a></li>
                        <li><a href="/zhengjian/lv">綠色工作證</a></li>
                        <li><a href="/zhengjian/anbao">安保證</a></li>
                    </ul>
                </div>
            </div>
        </div>
        {% endblock %}

        {% block content %}
        <div class="container">
            {% block page_content %}{% endblock %}
        </div>
        {% endblock %}

        {% block scripts %}
        {{ super() }}
        {{ moment.include_moment() }}
        {{ moment.lang('zh-CN') }}
        <script type="application/javascript">
            $SCRIPT_ROOT = {{ request.script_root|tojson|safe }}
        </script>

        {% endblock %}

index.html

        {% extends "base.html" %}

        {% block title %}資料管理系統(tǒng){% endblock %}

        {% block page_content %}
        <h1>本次會(huì)議共制卡<b id="sum"></b>張枉昏,具體情況如下:</h1>

        <div>
        {% if result %}
            {% for r in result %}
                <li id="result">{{ r[0]|getTypeRealName }}:{{ r[1] }}</li>
            {% endfor %}
        {% endif %}
        </div>
        <div>
        如果顯示效果不好,請(qǐng)點(diǎn)擊下載<a href="/static/Soft/Chrome.exe">谷歌瀏覽器</a>
        </div>
        {% endblock %}

        {% block scripts %}
        {{ super() }}
        <script type="text/javascript">
            $(function () {
                $sum=0;
               $('li#result').each(function () {
                   li = $(this);
                   text = li.text();
                   array = text.split(':');
                   $sum+=parseInt(array[1]);
               });
               $('#sum').text($sum);
            });
        </script>

        {% endblock %}

index.html是通過(guò)獲得后臺(tái)的數(shù)據(jù)通過(guò)ninja引擎渲染獲得的顯示頁(yè)面

0x024 數(shù)據(jù)對(duì)象持久化處理

最早開發(fā)的時(shí)候是用sqlite盏档,后來(lái)改用mysql

        from sqlalchemy import create_engine
        from sqlalchemy.orm import scoped_session, sessionmaker
        from sqlalchemy.ext.declarative import declarative_base
        #'sqlite:///./card.db'
        engine = create_engine('mysql+pymysql://root:root@localhost/card?charset=utf8', convert_unicode=False)
        # 創(chuàng)建數(shù)據(jù)庫(kù)引擎( 當(dāng)前目錄下保存數(shù)據(jù)庫(kù)文件)
        db_session = scoped_session(sessionmaker(autocommit=False,
                                             autoflush=False,
                                             bind=engine))
        Base = declarative_base()
        Base.query = db_session.query_property()

        def init_db():
        # 在這里導(dǎo)入所有的可能與定義模型有關(guān)的模塊凶掰,這樣他們才會(huì)合適地
        # 在 metadata 中注冊(cè)。否則,您將不得不在第一次執(zhí)行 init_db() 時(shí)
        # 先導(dǎo)入他們懦窘。
        import models
        Base.metadata.create_all(bind=engine)

0x025 數(shù)據(jù)實(shí)體定義

一個(gè)數(shù)據(jù)實(shí)體類的定義前翎,脫離了實(shí)際的數(shù)據(jù)庫(kù),很簡(jiǎn)單的完成CRUD的操作

    class User(Base):
        __tablename__ = 'User'

        id = Column(Integer, primary_key=True)
        name = Column(String(50), unique=True)
        type_id = Column(Integer, ForeignKey('CardType.id'))
        department = Column(String(250))
        status = Column(BOOLEAN, default=True)
        path = Column(String(500))
        updatetime = Column(String(500), default=datetime.datetime.now())
        batchlog = relationship('BatchLog', backref='users', lazy='dynamic')

        @hybrid_property
        def getUpdateTime(self):
            time = datetime.datetime.strptime(self.updatetime, '%Y-%m-%d %H:%M:%S.%f')

            return time - datetime.timedelta(hours=8)

0x03 開發(fā)

光靠上面的只言片語(yǔ)畅涂,想完成一個(gè)flask的demo港华,或許還是有點(diǎn)困難的,有問(wèn)題可以問(wèn)我午衰,或者看看flask的入門教程立宜,也可以看看鄙人的代碼。記錄一下掉過(guò)的坑臊岸。

0x031 中文編碼

python2.7處理中文永遠(yuǎn)繞不過(guò)的就是中文編碼的問(wèn)題橙数,那個(gè)該死的‘utf8’,下一次我一定用python3.5了

0x0311 mysql編碼

我怎么設(shè)置mysql的字符集

    show variables like 'character%';

mysql死活出來(lái)的亂碼帅戒,于是使用了下面這一招

engine = create_engine("mysql+pymysql://root:root@localhost/card?charset=utf8", convert_unicode=False)
# 創(chuàng)建數(shù)據(jù)庫(kù)引擎( 當(dāng)前目錄下保存數(shù)據(jù)庫(kù)文件)
db_session = scoped_session(sessionmaker(autocommit=False,
                                         autoflush=False,
                                         bind=engine))

0x0312 路徑中文編碼

普通變量灯帮,使用decode('utf8')函數(shù)

    type.decode('utf8')

路徑拼接,是用強(qiáng)制unicode的字符串

    rawpath = os.path.join(rawpath, u'記者證')

0x032 word文檔的仿宋字體設(shè)置

在docx的源碼逻住,-->Lib-->site-packages-->docx-->text-->font.py

    @name.setter
    def name(self,value):
        rPr = self._element.get_or_add_rPr()
        rPr.rFonts_ascii = value
        rPr.rFonts_hAnsi = value
        #加上下面一句钟哥,亞洲字體
        rPr.rFonts_eastAsia = value

一般的段落是

    acceptorparagraph.runs[0].font.name = u'仿宋_GB2312'
    acceptorparagraph._element.r_lst[0].rPr.rFonts.set(qn('w:eastAsia'), u'仿宋_GB2312')

表格的話是

    row_cells[0].paragraphs[0].runs[0].font.name = u'仿宋_GB2312'
    row_cells[0].paragraphs[0].runs[0].font.element.rPr.rFonts.eastAsia = u'仿宋_GB2312'

0x04 心得

其實(shí)整個(gè)程序開發(fā)還是費(fèi)了不少勁,但是成效還是很明顯了:

  1. 給我數(shù)據(jù)的人可以通過(guò)訪問(wèn)網(wǎng)頁(yè)來(lái)查看相關(guān)參會(huì)人員的是否已經(jīng)被成功接受
  2. 所有人都能通過(guò)網(wǎng)頁(yè)得知當(dāng)前的證卡制作情況
  3. 我理直氣壯的提交做好的證件瞎访,不會(huì)被人說(shuō)做漏了腻贰,也不會(huì)發(fā)生移交了卡發(fā)生丟失還賴我
  4. 我能在任何時(shí)間統(tǒng)計(jì)出已經(jīng)做了多少卡的數(shù)量,畢竟是工作量啊扒秸,不然總是個(gè)模糊數(shù)播演,豈不是“葫蘆僧盤葫蘆案”
  5. 移交證卡的數(shù)量和名單列表自動(dòng)生成,就不用每次都重新數(shù)鸦采,還容易出錯(cuò)宾巍,不然還說(shuō)不清楚交出去多少
  6. 連報(bào)賬材料都自動(dòng)生成了,以后再也不用費(fèi)時(shí)做這些體力活了渔伯,只要排版打印就好
  7. 只要我能說(shuō)清楚了我做了啥顶霞,那就意味著標(biāo)準(zhǔn)在我手里,獲得了標(biāo)準(zhǔn)的制定權(quán)就是拿到了游戲規(guī)則
最后編輯于
?著作權(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ō)我怎么就攤上這事∪唬” “怎么了歉摧?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)腔呜。 經(jīng)常有香客問(wèn)我叁温,道長(zhǎng),這世上最難降的妖魔是什么核畴? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任膝但,我火速辦了婚禮,結(jié)果婚禮上膛檀,老公的妹妹穿的比我還像新娘锰镀。我一直安慰自己,他們只是感情好咖刃,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著憾筏,像睡著了一般嚎杨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上氧腰,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天枫浙,我揣著相機(jī)與錄音,去河邊找鬼古拴。 笑死箩帚,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的黄痪。 我是一名探鬼主播紧帕,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼桅打!你這毒婦竟也來(lái)了是嗜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤挺尾,失蹤者是張志新(化名)和其女友劉穎鹅搪,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(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
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望矫钓。 院中可真熱鬧要尔,春花似錦、人聲如沸新娜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)概龄。三九已至还惠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間私杜,已是汗流浹背蚕键。 一陣腳步聲響...
    開封第一講書人閱讀 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

推薦閱讀更多精彩內(nèi)容

  • 22年12月更新:個(gè)人網(wǎng)站關(guān)停田篇,如果仍舊對(duì)舊教程有興趣參考 Github 的markdown內(nèi)容[https://...
    tangyefei閱讀 35,165評(píng)論 22 257
  • # Python 資源大全中文版 我想很多程序員應(yīng)該記得 GitHub 上有一個(gè) Awesome - XXX 系列...
    aimaile閱讀 26,448評(píng)論 6 428
  • GitHub 上有一個(gè) Awesome - XXX 系列的資源整理,資源非常豐富替废,涉及面非常廣。awesome-p...
    若與閱讀 18,629評(píng)論 4 418
  • 第五章 數(shù)據(jù)庫(kù) 序:什么是數(shù)據(jù)庫(kù) 數(shù)據(jù)庫(kù)按規(guī)則保存程序數(shù)據(jù)泊柬,程序發(fā)起查詢?nèi)』財(cái)?shù)據(jù)椎镣。Web 程序最常使用基于關(guān)系模型...
    科幻經(jīng)典閱讀 827評(píng)論 0 1
  • 這次活動(dòng)讓我們親眼看見了這些水質(zhì)的污染,讓我們切身的體會(huì)到水的重要性兽赁。減少污染状答,節(jié)約用水刻不容緩冷守。
    emmmmmm哦閱讀 60評(píng)論 0 0