做SRDP的过程中发现关系型数据库在实现问卷效果时比较困难,所以找了个时间熟悉了一下非关系型数据库,做了一个todo小demo。

视频演示地址

过程记录

下载安装mongodb,注意安装的时候不要勾选compass,我勾选之后直接卡住了。

安装Flask相关扩展:pip install Flask-PyMongo

Flask-PyMongo是在PyMongo基础上进行的封装,令其满足扩展的习惯性使用方式,具体操作需要查看PyMongo中的相关内容。两个扩展的文档:Flask-PyMongoPyMongo

过程中参考的两个博客:

  1. http://www.bjhee.com/flask-ext5.html
  2. https://towait.com/blog/flask-mongodb-crud/

过程中需要注意mongodb使用$配合其它关键字实现不同更新数据方式的方法。实现代码如下:

from flask import Flask, render_template, abort, redirect, url_for, request
from flask_bootstrap import Bootstrap
from flask_pymongo import PyMongo
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
from bson.objectid import ObjectId

from time import time

app = Flask(__name__)
# app配置

app.config['MONGO_DBNAME'] = 'flask'  # 数据库名
app.config['MONGO_URI'] = 'mongodb://localhost:27017/flask'
# 暂时不涉及用户名与密码
app.config['SECRET_KEY'] = 'balabala'  # wtf

mongo = PyMongo(app)
bootstrap = Bootstrap(app)


# 表单
class ContentForm(FlaskForm):
    content = StringField('Content', validators=[DataRequired()])
    submit = SubmitField('提交')

class DeleteForm(FlaskForm):
    submit = SubmitField('Delete')

class FinishForm(FlaskForm):
    submit = SubmitField('Finish')


# 数据模型
def create(content: str):
    body = {
        'content': content,
        'time': time(),
        'finished': False,
        'finished_time': None
    }
    return body


@app.route('/', methods=['GET', 'POST'])
def index():
    form = ContentForm()
    form_d = DeleteForm()
    form_f = FinishForm()
    if form.validate_on_submit():
        cur = create(form.content.data)     # 不需要要定义数据模型
        mongo.db.todos.insert_one(cur)
    res = mongo.db.todos.find()
    return render_template('index.html', records=res, form=form, form_d=form_d, form_f=form_f)


@app.route('/delete/<obj_id>', methods=['POST'])
def delete_record(obj_id):
    form = DeleteForm()
    if form.validate_on_submit():
        mongo.db.todos.delete_one({'_id': ObjectId(obj_id)})
    else:
        abort(400)
    return redirect(url_for('index'))


@app.route('/finish/<obj_id>', methods=['POST'])
def finish_record(obj_id):
    form = FinishForm()
    if form.validate_on_submit():
        print('dd')
        mongo.db.todos.update_one({'_id': ObjectId(obj_id)}, {
            '$set': {
                'finished': True,
                'finished_time': time()
            }
        })
    else:
        abort(400)
    return redirect(url_for('index'))

@app.route('/search', methods=['GET'])
def search_records():
    content = request.args.get('content', None)

    form = ContentForm()
    form_d = DeleteForm()
    form_f = FinishForm()
    if content is not None:
        res = mongo.db.todos.find(
            {'content': {"$regex": content}}
        )
    else:
        res = mongo.db.todos.find()
    return render_template('index.html', records=res, form=form, form_d=form_d, form_f=form_f)

if __name__ == '__main__':
    app.run()

页面模板文件:

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

{% block title %}To Do {% endblock %}

{% block content %}
    <h2>To Do List</h2>
    <form method="get" action="{{ url_for('search_records', content=content) }}">
    <input type="text" name="content"> <input type="submit" value="搜索">
    </form>
    <br>
    <form method="post" action="{{ url_for('index')}}">
    {{ form.csrf_token }}
    {{ form.content() }}
    {{ form.submit() }}
    </form>
    <h3>记录列表</h3>
    <ul>
    {% for record in records %}
    <li>
    <p>内容:{{ record['content'] }}</p>
    <p>创建时间:{{ record['time'] }}</p>
    {% if record['finished'] %}
        <p>状态:Finished</p>
        <p>完成时间 {{ record['finished_time'] }}</p>
    {% else %}
        <p>状态:Unfinished</p>
    {% endif %}
    {% set p = record['_id']~'' %}
    <form method="post" style="float: left" action="{{ url_for('delete_record', obj_id=p) }}">
        {{ form_d.csrf_token }}
        {{ form_d.submit() }}
    </form>
    <form method="post" action="{{ url_for('finish_record', obj_id=p) }}">
        {{ form_f.csrf_token }}
        {{ form_f.submit() }}
    </form>
    </li>
    {% endfor %}
    </ul>
{% endblock %}