程序设计
应用代码见此 / web应用地址 / 合作伙伴jahowz博文连接
实现功能
- 难度分级和题数选择
- 错题计数(本次和总次数)和错题集
- 做题计时功能
- 多语言选择(用户没选择会根据HTTP头来自动选择)
- 支持小数计算
- 限定用户输入(不允许非数字、/和.)
原本的控制台版本是用python
实现的,本次使用Flask
开发web端
应用。整个应用的树状图如下:
pair_work
├── data
│ └── calc.db
├── func.py
├── README.md
├── static
│ └── timer.js
├── templates
│ ├── error_question.html
│ ├── index.html
│ ├── layout.html
│ ├── question_paper.html
│ └── result.html
└── views.py
3 directories, 10 files
- data目录下是数据库文件
- func.py是功能模块的代码
- static目录下是用于计时功能的js代码
- templates目录下是页面的html文件
- views.py是视图模块的代码
视图模块
views.py
里面存放视图函数,用在用户端和服务端中间处理。
比如会判断用户端使用的语言,自动选择语言并写到session
中,选择相应的模板渲染返回给用户;根据用户的操作选择相应的功能函数进行处理。
主要代码如下(请到coding.net上查看最新的代码):
@app.route('/', methods=['GET', 'POST'])
def index():
session['lang'] = request.form.get("lang",0)
s = session['lang']
if s == '1': # zh-cn
return render_template("index.html",selnum="0",lang=zh_cn)
elif s == '2': # zh-tw,zh-hk
return render_template("index.html",selnum="1",lang=zh_hk)
elif s == '3': # en
return render_template("index.html",selnum="2",lang=en)
else:
al = request.headers['ACCEPT_LANGUAGE']
if al.startswith("zh-TW") or al.startswith("zh-HK"):
return render_template("index.html",selnum="1",lang=zh_hk)
elif al.startswith("en"):
return render_template("index.html",selnum="2",lang=en)
else:
return render_template("index.html",selnum="0",lang=zh_cn)
@app.route('/question_paper/', methods=['GET', 'POST'])
def question_paper():
if request.method == 'POST':
sel = request.form.get('easy','0') + request.form.get('medium','0') + request.form.get('hard','0')
num = request.form.get('num',0)
return render_template('question_paper.html', questions=main(sel, num),lang=all_lang[language_choice()])
return redirect(url_for('index'))
@app.route('/result/', methods=['GET', 'POST'])
def result():
if request.method == 'POST':
user_answer = []
num = get_num()
for i in range(1,num+1):
# 'x' stands for the user has not input answer
user_answer.append(request.form.get('t'+str(i),'x'))
# format of results is [{'question':'1+3*2','user_answer':'6','real_answer':'7','flag':0},{'question':'1+3*2','user_answer':'7','real_answer':'7','flag':1}]
t = compare(user_answer) # 0->results , 1->current_error
return render_template('result.html', results=t[0], timer=request.form.get('timer','0'), current_error=t[1], total_error=len(error_reader()),lang=all_lang[language_choice()])
return redirect(url_for('index'))
@app.route('/error_question/', methods=['GET'])
def error_question():
e = error_reader()
return render_template('error_question.html', total_error=len(e), error_questions=e,lang=all_lang[language_choice()])
功能模块和数据模块
数据模块主要是存储在data/
文件夹下的数据,最初是文本存储,改版后变成了数据库,这一块主要是让功能模块取用的。
功能模块主要存在func.py
里面,功能模块的实现是有jahowz基于他上一次做的控制台版本的程序改写并新增功能而来,期间会根据我这边的需求去改动。
内部具体实现细节完全由他来完成,我只会和他交流需要对接的地方,比如我需要一个功能,能传递给他什么参数,他需要给我返回什么结果。
模板
templates
目录下主要存放了html模板,视图在接受用户传来的信息,并调用功能模块处理完后,会渲染里面相应的html模板,把结果返回给用户端。
html文件主要使用模板继承,layout.html
为基文件,其他页面都是基于这个页面继承而来,相应的模块可以根据相应的页面更改,其他的注入头部和尾部基本一致就都通过继承而来。
程序运行展示
首先运行程序,访问主页可以看到,有语言选择,难度选择和题量:
之后出现相应题量的题目,并开始计时:
用户答完题提交后,显示本次答题结果,可以选择再做,也可以看看以前错的题目:
错题集里收录了以前做错的题目。
总结
分模块是一个很好的设计思想,本次我们主要把整个项目分了四大模块:视图
、功能
、数据
和模板
。相应的模块主要完成对应的功能,这样的好处在于,不同的模块进行改动甚至大改版也不会影响到别的模块。比如jahowz负责的功能模块内部算法改变,对于我负责的视图模块没有半点影响,数据模块由文本改成数据库,也依然毫无影响。这为整个应用系统的升级带来集大的便利。
最后很感谢jahowz
的大力支持,给他需求,就能很快得到方案和成果。