zoukankan      html  css  js  c++  java
  • Flask:操作SQLite3(0.1)

    Windows 10家庭中文版,Python 3.6.4,Flask 1.0.2

    本文介绍了第一次在Flask框架中操作SQLite3数据库的测试,参考了官网的文档Using SQLite 3 with Flask,直接使用了里面定义

    的几个函数:init_db、get_db、close_connection、make_dicts,另外,自己编写了视图(View)函数实现添加、读取操作。

    本测试项目的目标

    -使用建模文件初始化数据库成功

    -连接数据库成功

    -关闭数据库成功

    -添加数据成功

    -读取数据成功,并成功返回到页面

    测试步骤

    1.建立空的SQLite3数据库文件 和 数据库建模文件

    前面一篇关于SQLite3的文章有介绍,使用sqlite3.exe即可;

    数据库建模文件,参考SQLite官方文档SQL As Understood By SQLite建立;

    下面是我的建模文件内容:

    1 DROP TABLE IF EXISTS post;
    2 CREATE TABLE post (
    3     id INTEGER PRIMARY KEY AUTOINCREMENT,
    4     body VARCHAR(500) NOT NULL,
    5     created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
    6 );

    如果原数据库存在,就删除,然后建立新的。

    数据表post,包括id、body、created三个字段,其中,body字段为提交的消息,created为消息存放到数据库的时间。

    建立好的数据库文件和建模文件放到项目的db文件夹下:

    说明,数据库文件和建模文件不一定要放到db文件夹下,也可以放到Flask项目的根目录下(Q:是否可以放到项目之外呢?不建议。),只要程序中把相关路径输入正确即可。

    2.编写Flask项目文件main.py(单模块项目)

    将文档Using SQLite 3 with Flask中的一些代码拷贝到many.py中。

     1 from flask import * # 导入flask模块下的所有元素
     2 import sqlite3 # 导入sqlite3模块
     3 
     4 app = Flask('Posts') # 建立Flask应用
     5 
     6 DATABASE = 'db/posts.db' # 数据库文件地址
     7 DATABASE_INIT_FILE = 'db/init.sql' # 数据库建模文件地址
     8 
     9 # init_db()
    10 def init_db(): # 此函数要使用 数据库建模文件 初始化数据库:建立post表(Initial Schemas)。此函数在命令行中使用,仅一次,再次使用会删除数据库中已有数据11     with app.app_context(): # 官网文档说了原因:不是在Web应用中使用,而是在Python Shell中使用时需要此语句Connect on Demand)。
    12         db = get_db()
    13         with app.open_resource(DATABASE_INIT_FILE, mode='r') as f: # with语句用法!
    14             db.cursor().executescript(f.read()) # 执行建模文件中的脚本
    15         db.commit() # 提交事务
    16 
    17 # make_dicts()
    18 def make_dicts(cursor, row): # 将查询返回的数据的转换为字典类型,这样会跟方便使用。此函数会在get_db()函数中用到,赋值给db.row_factory。
    19     return dict((cursor.description[idx][0], value)
    20                 for idx,value in enumerate(row))
    21 
    22 # get_db()
    23 def get_db(): # 获取数据库连接
    24     db = getattr(g, '_database', None) # g对象时一个Flask应用的公共对象(和request、session一样),用于存储用户的数据——整个应用共享!
    25     if db is None:
    26         db = g._database = sqlite3.connect(DATABASE) # 建立数据库连接
    27         db.row_factory = make_dicts # 转换默认的查询数据类型为字典类型,也可以使用sqlite3.Row
    28     return db # 返回数据库连接,可能返回为None
    29 
    30 # close_connection()
    31 @app.teardown_appcontext # 这个装饰器用于实现在请求的最后自动关闭数据库连接的功能
    32 def close_connection(exception): # 关闭数据库连接
    33     db = getattr(g, '_database', None)
    34     if db is not None:
    35         db.close()

    说明,在誊写代码过程中,把cursor.description写错了,直到最后运行程序才发现了错误。

    以上,初始化数据库——只执行一次、获取数据库连接、关闭数据库连接的程序都有了。接下来,建立一个视图函数测试数据库连接、关闭数据库连接是否正常执行。

    注意,在此时之前需要再get_db、close_connection函数中添加调试语句,print或者app.logger都可以。

    1 @app.route('/testdb')
    2 def testdb():
    3     get_db()
    4     return "After test"

    然后,启动Flask项目,使用浏览器访问/testdb,检查项目命令行即可看到添加的调试语句——提示错误就继续修改。

    3.使用 建模文件 初始化 数据库文件

    这个时候需要用到上面的init_db()函数了。

    在文档Using SQLite 3 with Flask的Initial Schemas中有介绍,将Flask项目模块的init_db()函数导入,再执行即可。

    下面是我的测试情况:成功 按照建模文件 建立 数据表post

    注意,在Python Shell执行上面的命令时,需要保证当前目录为Flask项目所在目录。

    4.建立测试项目需要视图函数(View functions)

    本测试项目需要实现发布消息、展示消息的功能(但并没有做到同一个页面上),因此,建立了三个视图函数来实现目标:

    4.1 home()

    首页,返回一个模板用于添加post。

    此模板文件仅包含静态内容,因此,render_template只有一个参数。

    1 # path: /
    2 # show posts
    3 @app.route('/')
    4 def home():
    5     return render_template('temp.html')

    模板文件主要内容:定义表单,action为“pureadd”

    1 <form action="pureadd" method="post">
    2     <textarea name="newpost" style="200px;height:100px;" maxlength="500"></textarea><br />
    3     <input type="submit" value="添加" /> 
    4 </form>
    5 <a href="/pureshow">展示帖子</a><br />

    页面如下:

    4.2 pureadd()

    一个单纯地(pure)用于添加一条post到数据库的视图函数,会对参数进行校验、发生错误时会返回错误的信息等。

    仅支持POST方法的请求。

    此视图的返回信息中还包括跳转到添加页面、展示页面的链接。

     1 # pure add page for test
     2 @app.route('/pureadd', methods=['POST'])
     3 def pureadd():
     4     # step 1. get the new post and check the data
     5     newp = ''
     6     try:
     7         newp = request.form['newpost']
     8     except:
     9         return 'ERROR: Invalid form parameters!'
    10     
    11     print('newp = "', newp, '"')
    12     
    13     newp2 = newp.strip() # 清理post两遍的空格,然后赋值给新变量——此时旧变量没有改变
    14     
    15     if newp2 == '':
    16         return 'Warning: New post is empty!<br/>' 
    17             '<a href="/">继续添加</a><br/>' 
    18             '<a href="/pureshow">展示帖子</a><br />'
    19     
    20     # step 2.write the new post into database
    21     sqlmode = 'INSERT INTO post(body) VALUES(?)' # 添加数据的SQL语句,占位符使用问号(?)。需要注意的是,如果是MySQL,占位符是百分号(%)。
    22     try:
    23         db = get_db()
    24         cursor = db.cursor()
    25         cursor.execute(sqlmode, (newp2,))
    26         cursor.close() # 关闭cursor。Q:是否一定要关闭呢?不关闭有什么影响?
    27         db.commit() # 需要commit,否则,数据不会更新到数据库
    28     except Exception as e:
    29         return '<span style="color:red;">INFO: New post added failed <br/> %s</span><br/>' 
    30             '<a href="/">继续添加</a><br/>' 
    31             '<a href="/pureshow">展示帖子</a><br />' % str(e)
    32     else:
    33         return 'INFO: New post added <br/><pre>[%s]</pre><br/>' 
    34             '<a href="/">继续添加</a><br/>' 
    35             '<a href="/pureshow">展示帖子</a><br />' % newp

    成功添加一条数据:

    数据库中显示添加的数据:

    4.3 pureshow()

    此视图函数用于 展示数据库中的数据。

    将查询到的数据直接返回到 模板文件showall.html 中。

    注意,需要提一下前面get_db()函数中的设置db.row_factory为make_dicts。如果没有这个赋值的话,模板文件的解析数据方式将会改变。

     1 # pure show page for test
     2 @app.route('/pureshow')
     3 def pureshow():
     4     sqlmode = "SELECT * FROM post ORDER BY created DESC"
     5     rv = []
     6     try:
     7         db = get_db()
     8         cursor = db.execute(sqlmode)
     9         rv = cursor.fetchall()
    10         cursor.close()
    11     except Exception as e:
    12         print(e)
    13         abort(500)
    14     else:
    15         return render_template('showall.html', posts=rv)

    模板文件showall.html的主要内容:使用for循环将pureshow()函数返回的内容展示出来

    1 <div id="postslist">
    2     {% for post in posts %}
    3         <div class="post_item" id="post{{ post.id }}">
    4             {{ post.body }}<br/>
    5             {{ post.created }}
    6         </div>
    7     {% endfor %}
    8 </div>
    9 <a href="/">继续添加</a>

    /pureshow页面展示内容如下:

    注意,数据库中保存的时间为UTC时间,在实际应用中,展示出来时还需要添加对应的时差。

    参考链接

    Using SQLite 3 with Flask

    廖雪峰官网 之 使用SQLite(关于占位符)

    后续

    上面的方法很简单,在Flask提供的扩展中,有一个叫做SQLAlchemy的,使用它可以更高效地操作各种数据库,所以,下一步就是学习并使用它了。

    官方文档SQLAlchemy in Flask中有介绍,看过一遍了,现在,该实践了。

    前面做的项目都是基于单个的模型文件的,后面需要升级:基于package的方式使用Blueprint,这两个是重点啊!

    在官网的Tutorial会有关于SQLAlchemy、Blueprint的介绍,也是需要参考的。

    Flask,还需要以周计的时间才能熟练使用啊。

    自己没有做过完整的Web应用,在URL设计等方面存在一些挑战,因此,这个测试项目才会如此simple。

    本来还想实现用户登录、退出等“稍微复杂”的功能的——最初的想法,最后都只能放弃了。

    我想,在熟悉了SQLAlchemy、Blueprint后,Web开发的功力会有很大提高的。

    对了,还有就是 怎么提供数据接口给前端,比如RESTful API等,都是需要熟练的。

  • 相关阅读:
    深圳市共创力为某上市公司提供的整机工程研发管理咨询项目顺利结项!
    2017.9.16~17,热烈庆祝共创力罗老师《敏捷MINI体验式实战培训》在某大型企业成功举办!
    2017年8月20日,杨学明老师为深圳某著名医疗企业提供内训课程服务!
    2017年8月18日~19日,杨学明老师为深圳某著名汽车电子企业提供内训课程服务!
    Python使用Plotly绘图工具,绘制饼图
    Python安装第三方包(模块/工具)出现链接超时,网速慢,安装不上的问题如何解决
    Python使用Plotly绘图工具,绘制甘特图
    Python使用Plotly绘图工具,绘制水平条形图
    Python使用Plotly绘图工具,绘制柱状图
    Python使用Plotly绘图工具,绘制气泡图
  • 原文地址:https://www.cnblogs.com/luo630/p/9073879.html
Copyright © 2011-2022 走看看