小试牛刀Flask

在情人节这天写技术文档,太没有情调了。不过有情人的话,哪天不是情人节,哈哈。

0x00 背景

在流程不太明确,每个人的责任边界比较模糊的时候,软件需求与产品都是个深坑。

0x001 未必是坑

对于在这个工作的经办人而言,这个时候的需求与产品会是:

  1. 一个关键的流程梳理工具
  2. 划分管理责任的重要依据
  3. 项目工作流程实时可见的重要手段
  4. 问题追溯定位的重要来源

0x002 要求不低

理想很丰满,毕竟在一片混沌之中,有个人杀出一条路之后,此后也就有路了。所以,为了完成这个目标,系统应该要具备:

  1. 有一个可以快速开发的框架,至少包括数据持久化,后台处理与前台交互
  2. 需要一个随需应变(On Demand)的设计架构,因为业务会随时的改,包括原来起初为一个会议参会人员设计的功能要变成多个会议同时进行的功能
  3. 开发起来时间一定要短,效果一定不能太差,而且必须通过网络访问

严格来说,上面那些需求都是非功能需求,那功能需求是:

  1. 能够通过处理相片的规则化命名,新建参会人员的姓名、单位、证卡类型、参加会议的种类
  2. 保留那些命名错误的照片,等待手工处理,总有一部分人提交的数据每次都有问题
  3. 整理完一个批次的入库资料后,会打包并新建一个excel表格,经校验完之后生成一个zip压缩包,同时将证件的状态变成“送打印”
  4. 每次打包的资料都是当前证件类型中未打印的资料
  5. 卡证制作完毕后对每张证件进行校验,核校数据,通过点击“核校”按钮,将证件状态变成“已核校”
  6. 对成产完成的证卡信息自动生成移交文档,通过选择批次数来选定数据,并合并同类证卡的人员名单
  7. 会议结束后,整理出每种证件制作的数量,并打印名单

在功能需求中提到的工作,就是我实际工作的内容,数据提交很零散,要汇总成一个大表,耗费的时间比较长,没有一个确切的统计数据和列表,核对制作证卡的时候就容易出错,上面的活不是很难,就是很反锁,很容易错,而且时候要做统计的时候又要花去不少的时间,此外还可能有多次提交制卡信息的单位,一个人实在是hold不住啊。

事情做久了,自己对业务熟悉了,别人就不清楚了,所以到头来重担还得自己挑。所以拿起武器,开干,核心程序写了三个晚上,白天在真实数据与环境下调试了几天,主要是那些不按照规定乱命名的文件名,让我写了很多异常处理的语句。

0x01 准备

我能拿起来的开发语言无非就是asp.net、java、php、python,至于javascript的什么Node.js,什么angularJs,什么TypeScript,今年应该就没问题了。备选的框架有:

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

为了保持技术的连贯性,我选择python,框架的选择是一个难题,选熟悉的django还是选更流行的flask,看了一下午的文档之后最终选择,挑战自己,选择从未碰过的flask。

0x011 配置环境

0x0111 选择Anaconda

选择Anaconda python2.7 的发行版,下次选择python3.5的,有windows,mac与linux版本。

0x0112 选择pycharm

工欲善其事,必先利其器

Python的IDE有很多,当然你也可以选择不用,但是我选的是Pycharm

0x0113

需要安装的一些插件

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

缺了的套件都可以用 pip install来安装

0x02 架构

大体来说,代码架构是这样的

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的主要内容是包括页面显示,后台处理,Ajax服务以及自定义的页面面模版管道
  • database.py与models.py主要是做数据持久化,以及数据实体的处理
  • home.py是处理flask部署的时候设置

0x022 简单的后台处理流程

而页面处理主要是:

    """
    初始化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,资源的访问路径
  2. def index(): 定义一个函数,可以与路径名不一样,但是必须唯一,不支持函数重载
  3. return render_template('index.html', result=result) 啪啦啪啦处理完了之后,通过render_template来与模版一起渲染,通过ninja引擎,来实现展现页面

0x023 简单的页面前端实现

必须实现框架的基本模版,扩展的是bootstrap框架的模版

base.html

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

    {% block title %}资料管理系统{% 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">参会人员管理系统</a>
                </div>
                <div class="navbar-collapse collapse">
                    <ul class="nav navbar-nav">
                        <li><a href="/zhengjian/jizhe">记者证</a></li>
                        <li><a href="/zhengjian/lan">蓝色工作证</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 %}资料管理系统{% endblock %}

        {% block page_content %}
        <h1>本次会议共制卡<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>
        如果显示效果不好,请点击下载<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是通过获得后台的数据通过ninja引擎渲染获得的显示页面

0x024 数据对象持久化处理

最早开发的时候是用sqlite,后来改用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)
        # 创建数据库引擎( 当前目录下保存数据库文件)
        db_session = scoped_session(sessionmaker(autocommit=False,
                                             autoflush=False,
                                             bind=engine))
        Base = declarative_base()
        Base.query = db_session.query_property()

        def init_db():
        # 在这里导入所有的可能与定义模型有关的模块,这样他们才会合适地
        # 在 metadata 中注册。否则,您将不得不在第一次执行 init_db() 时
        # 先导入他们。
        import models
        Base.metadata.create_all(bind=engine)

0x025 数据实体定义

一个数据实体类的定义,脱离了实际的数据库,很简单的完成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 开发

光靠上面的只言片语,想完成一个flask的demo,或许还是有点困难的,有问题可以问我,或者看看flask的入门教程,也可以看看鄙人的代码。记录一下掉过的坑。

0x031 中文编码

python2.7处理中文永远绕不过的就是中文编码的问题,那个该死的‘utf8’,下一次我一定用python3.5了

0x0311 mysql编码

我怎么设置mysql的字符集

    show variables like 'character%';

mysql死活出来的乱码,于是使用了下面这一招

engine = create_engine("mysql+pymysql://root:root@localhost/card?charset=utf8", convert_unicode=False)
# 创建数据库引擎( 当前目录下保存数据库文件)
db_session = scoped_session(sessionmaker(autocommit=False,
                                         autoflush=False,
                                         bind=engine))

0x0312 路径中文编码

普通变量,使用decode('utf8')函数

    type.decode('utf8')

路径拼接,是用强制unicode的字符串

    rawpath = os.path.join(rawpath, u'记者证')

0x032 word文档的仿宋字体设置

在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 心得

其实整个程序开发还是费了不少劲,但是成效还是很明显了:

  1. 给我数据的人可以通过访问网页来查看相关参会人员的是否已经被成功接受
  2. 所有人都能通过网页得知当前的证卡制作情况
  3. 我理直气壮的提交做好的证件,不会被人说做漏了,也不会发生移交了卡发生丢失还赖我
  4. 我能在任何时间统计出已经做了多少卡的数量,毕竟是工作量啊,不然总是个模糊数,岂不是“葫芦僧盘葫芦案”
  5. 移交证卡的数量和名单列表自动生成,就不用每次都重新数,还容易出错,不然还说不清楚交出去多少
  6. 连报账材料都自动生成了,以后再也不用费时做这些体力活了,只要排版打印就好
  7. 只要我能说清楚了我做了啥,那就意味着标准在我手里,获得了标准的制定权就是拿到了游戏规则
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,454评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,553评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,921评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,648评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,770评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,950评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,090评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,817评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,275评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,592评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,724评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,409评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,052评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,815评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,043评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,503评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,627评论 2 350

推荐阅读更多精彩内容