首发于Hello, Flask!
Flask实践:计时器

Flask实践:计时器

Demo体验:计时器 - Hello, Flask!
难度:1
涉及知识点:URL变量

- - - - -

我们经常在一些网站上看到倒计时,比如购物网站上的秒杀倒计时,或是考试网站上的距离高考还剩多少天……

我们今天就用Flask和JavaScript(jQuery)来实现一个在线计时器,具体的User Story:

项目结构

|-Timer-Flask 项目名称
    |-app.py
    |-templates/  模板文件夹
        |-index.html  
    |-static/
        |-beep.mp3  计时结束铃声
        |-favicon.ico  站点图标
        |-style.css
        |-js/
            |-progressbar.js
            |-jquery.min.js
            
    |-venv/  虚拟环境

实现代码

主程序:app.py

import re
from flask import Flask, render_template, url_for, redirect, request, flash

app = Flask(__name__)
app.config['SECRET_KEY'] = 'a very secret string'


@app.route('/')
def index():
    return redirect(url_for('timer', num=11*60+11))


@app.route('/<int:num>s')
@app.route('/<int:num>')
def timer(num):
    return render_template('index.html', num=num)


@app.route('/custom', methods=['GET', 'POST'])
def custom():
    time = request.form.get('time', 180)
    # 使用正则表达式来验证输入的字符
    m = re.match('\d+[smh]?$', time)
    if m is None:
        flash(u'请输入一个有效的时间,例如34、20s、15m、2h')
        return redirect(url_for('index'))
    if time[-1] not in 'smh':
        return redirect(url_for('timer', num=int(time)))
    else:
        type = {'s': 'timer', 'm': 'minutes', 'h': 'hours'}
        return redirect(url_for(type[time[-1]], num=int(time[:-1])))


@app.route('/<int:num>m')
def minutes(num):
    return redirect(url_for('timer', num=num*60))


@app.route('/<int:num>h')
def hours(num):
    return redirect(url_for('timer', num=num*3600))


@app.errorhandler(404)
def page_not_fouond(e):
    flash(u'访问地址出错了,鼠标放在问号上了解更多: )')
    return redirect(url_for('timer', num=244))

计时的功能主要用JavaScript(jQuery)实现,在index.html,传递变量给JavaScript:

{% block scripts %}
<script>
    var Minutes = {{ num }};
</script>
{% endblock %}

另外,在这个APP里,因为表单很小,所以没有使用Flask-WTF。表单部分:

<form method="POST" action="{{ url_for('custom') }}" style="display:inline">
    <input name="time" class="time-input" placeholder="example: 12/30s/20m/2h">
    <input type="submit" class="startButton" value="START">
</form>

然后在视图函数里,我使用request来获取数据,使用正则表达式验证数据:

@app.route('/custom', methods=['GET', 'POST'])
def custom():
    # 设置180为默认值,避免提交空白表单产生400错误
    time = request.form.get('time', 180) 
    # 使用正则表达式验证数据
    m = re.match('\d+[smh]?$', time)
    if m is None:
        flash(u'请输入一个有效的时间,例如34、20s、15m、2h')
        return redirect(url_for('index'))
    if time[-1] not in 'smh':
        return redirect(url_for('timer', num=int(time)))
    else:
        type = {'s': 'timer', 'm': 'minutes', 'h': 'hours'}
    return redirect(url_for(type[time[-1]], num=int(time[:-1])))

下一次会谈一下表单的几种不同的验证方式和一些处理技巧。

完整的实现见源码(链接在底部),欢迎fork和patch(或是star:)。

相关知识点

  • URL变量

大部分现代的网站(app)都会有一个美观简洁的URL,比如example.com/user/kitty。在Flask里,我们通过在URL里设置变量来实现这个功能,比如说上面的URL,对应的路由就是:

app.route('/user/<username>')

这个<variable_name>可以作为参数传递到视图函数里,我们还可以使用Flask提供的转换器,以<converter:variable_name>的形式来转换变量:

@app.route('/user/<username>')
def show_user_profile(username):
    # show the user profile for that user
    return 'User %s' % username

@app.route('/post/<int:post_id>')
def show_post(post_id):
    # show the post with the given id, the id is an integer
    return 'Post %d' % post_id

Flask支持的所有转换器可以访问Quickstart - Flask 1.0.2 documentation查看。

使用这个特性,计时器实现了在地址后填入参数就可以进入相应的计时。

最终效果



DEMO:timertimer.herokuapp.com

源码:github.com/helloflask/t

- - - - -

更多关于Flask的优质内容,欢迎关注Hello, Flask! - 知乎专栏

编辑于 2018-06-14

文章被以下专栏收录