一个简单地flask应用
/flaskr /static /template 用户可以通过HTTP访问static文件夹中的文件,这里也是css和javascript文件存放位置,flask将会在templates文件夹中寻找Jinja2模板, 要支持SQLite,将下列文件放入schema.sql drop table if exists entries; create table entries( id interger primary key autoincrement, title string not null, text string not null); 在flaskr.py中, import sqlite3 from flask import Flask,request,session,g,redirect,url_for,abort,render_template,flash #configuration DATABASE = ‘/tmp/flaskr.db‘ DEBUG = True SECRET_KEY = ‘development key‘ USERNAME = ‘admin‘ PASSWORD = ‘default‘ 创建应用,在同一文件中配置初始化: app = Flask(__name__) app.config.from_object(__name__) from_object()将会寻找给定的对象(如果他是一个字符串),搜寻里面定义的全部大写的变量, 从配置文件加载配置是from_envvar()所做的,用于替换from_object() app.config.from_envvar(‘FLASKr_SETTINGS‘,silent=True) 这种设置方法我们可以设置一个名为FLASKR_SETTINGS环境变量来设定一个配置文件载入之后是否覆盖默认值,静默开关告诉FLask不去关心这个环境变量键值是否存在 secret_key是需要为了保持客户端的会话安全, 添加一个轻松连接到指定数据库的方法,这个方法用于请求时打开一个连接. def connect_db(): return sqlite3.connect(app.config[‘DATABASE‘]) 如果想要把那个文件当做独立应用来运行,只需要加上: if? __name__ == ‘__main__‘: app.run() 顺利开始运行这个应用.使用如下命令: python flaskr.py? ? 创建数据库 Flaskr是一个使用关系型数据库的应用程序,这样的系统需要一个模式告诉他们如何存储信息,因此在首次启动服务器之前,创建数据库模式,可以通过管道把schema.sql作为sqlite3命令的输入来创建这个模式,命令如下: sqlite3 / tmp/flaskr.db <schema.sql> 这种方法的缺点是需要安装sqlite3命令,而并不是每个系统都有安装,必须提供数据库的路径,否则将报错, 可以添加一个函数来初始化数据库 首先从contextlib包中导入contextlib.closing()函数,并且在flaskr.py文件中添加如下的内容; from contextlib import closing 接着可以创建一个称为init_db函数,该函数用来初始化数据库,我们可以使用之前定义的connect_db函数,添加这样的函数: def init_db(): with closing(connect_db()) as db: with app.open_resource(‘schema.sql‘) as f: db.cursor().executescript(f.read()) db.commit() closing()助手函数允许我们在with块中保持数据库连接可用,应用对象的open_resource()方法在其方框外也支持这个功能,因此可以在with块中直接使用,这个函数从资源位置(你的flaskr文件夹)中打开一个文件,并且允许读取 当我们连接到数据库时会得到一个数据库连接对象,这个对象提供给我们一个数据库指针, ? 请求数据库连接: 在函数中需要数据库连接,在请求之前初始化他们,请求结束后自动关闭 Flask允许我们使用before_request(),after_request()和teardown_request()装饰器来实现这个功能: @app.before_request def before_request(): g.db = connect_db() @app.teardown_request def teardown_request(exception): g.db.close() 使用before_request()装饰器的函数会在请求之前被调用而且不带参数.使用after_request()装饰器的函数会在请求之后被调用且传入将要发给客户端的响应.他们必须返回那个响应对象或是不同的响应对象,但当异常被抛出时,他们不一定会被执行,并不允许修改请求,返回的值会被忽略.如果在请求已经被处理的时候抛出异常,他会被传递到每个函数,否则会传入一个None 我们把当前的数据库连接保存在Flask提供的g特殊对象中,这个对象只能保存一次请求的信息,并且在每个函数里都可用,不要用其他对象来保存信息,因为在多线程环境下将不再可行,特殊的对象g在后台有一些神奇的机制来保证他在做正确的事情. ? 视图函数 显示条目: 这个视图显示所有存储在数据库的条目,他监听着应用的根地址以及会从数据库中查询标题和内容,id值最大的条目将在前面,从游标返回行是按select语句中声明的列组织的元组,视图函数将会把条目作为字典传入show_entries.html模板及返回渲染结果 @app.route(‘/‘) def show_entries(): cur = g,db.execute(‘select title,text from entries order by id desc‘) entries = [dict(title=row[0],text=row[1])for row in cur.fetchall())] return render_template(‘show_entries.html‘,enries=entries) 添加新条目 这个视图允许登录的用户添加新的条目,他只回应POST请求,实际的表单是显示在show_entries页面,如果一些工作正常,我们用flash()向下一个请求闪现一条信息并且跳转回show_entries页: @app.route(‘/add‘,methods=[‘POS‘]) def add_entry(): if not session.get(‘logged_in‘): abort(401) g.db.execute(‘insert into entries(title,text) values (?,?)‘,[request.form[‘title‘],request.form[‘text‘]]) g.db.commit() flash(‘New entry was successful posted‘) return redirect (url_for(‘show-entries‘)) ? 登录和注销 这些函数是用于用户登录以及注销,依据在配置中的值登录时检查用户名和密码并且在会话中设置logged_in键值,如果用户登录成功,logged_in键值被设置成True,并跳转回show_entries页,此外,会有消息闪现来提示用户登入成功,如果发生错误,模板会通知并提示重新登录: @app.route(‘/login‘,methods=[‘GET‘,‘POST‘]) def login(): error = None if request.method == ‘POST‘: if request.form[‘username‘] != app.config[‘USERNAMe‘]: error = ‘Invalid username‘ elif request.form[‘password‘] != app.config[‘PASSworD‘]: error = ‘Invalid password‘ else: session[‘logged_in‘] = True flash(‘You were logged in‘) return redirect(url_for(‘show_entries‘)) return render_template(‘login.html‘,error=error) 另一方面注销函数会从会话中移除了logged_in键值,这里我们使用一个大绝招,如果你使用字典的pop()方法并传入第二个参数(默认),这个方法会从字典中删除这个键,如果这个键不存在则什么都不做,我们不需要检查用户是否登录 @aa.route(‘/lgout‘) def logout(): session.pop(‘logged_in‘,None) flash(‘You were logged out‘) return redirect(url_for(‘show_entries‘)) ? 模板 模板使用Jinja2语言以及默认开启自动转义,意味着除非使用Markup标记或在模板中使用|safe过滤器,否则jinja2会确保特殊字符比如<或>被转义成等价的XML实体,session字典在模板中同样可用的,注意在Jinja中你可以访问不存在的对象/字典属性或成员,及时键不存在仍然可以正常工作 <title>Flaskr</title> <link rel=stylesheet type=text/css href="{{ url_for(‘static‘,filename=‘style.css‘) }}"> <div class=page> <h1>Flaskr</h1> <div class=metanav> {% if not session.logged_in %} <a href="{{ url_for(‘login‘) }}">log in</a> {% else %} <a href="{{ url_for(‘logout‘) }}">log out</a> {% endif %} </div> {% for message in get_flashed_messages() %} <div class=flash>{{ message }}</div> {% endfor %} {% block body %}{% endblock %} </div>
show_entries.html 这个模板继承了上面的layout.html模板来显示信息,注意for遍历了所有用render_template()函数传入的信息,同样告诉表单提交到add_entry函数且使用HTTP的POST方法: {% extends "layout.html" %} {% block body %} {% if session.logged_in %} <form action="{{ url_for(‘add_entry‘) }}" method=post class=add-entry> <dl> <dt>Title: <dd><input type=text size=30 name=title> <dt>Text: <dd><textarea name=text rows=5 cols=40></textarea> <dd><input type=submit value=Share> </dl> </form> {% endif %} <ul class=entries> {% for entry in entries %} <li><h2>{{ entry.title }}</h2>{{ entry.text|safe }} {% else %} <li><em>Unbelievable. No entries here so far</em> {% endfor %} </ul> {% endblock %}
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |