数据库URL必须保存到Flask配置对象的SQLALCHEMY_DATABASE_URI键中。将SQLALCHEMY_COMMIT_ON_TEARDOWN键,将其设为True时,每次请求结束后都会自动提交数据库中的变动。
简单的配置SQLite数据库
from flask_sqlalchemy import SQLAlchemy
basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'
app.config['SQLALCHEMY_DATABASE_URI'] =\
'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
定义模型
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
users = db.relationship('User', backref='role', lazy='dynamic')
def __repr__(self):
return '' % self.name
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
def __repr__(self):
return '' % self.username
tablename定义在数据库中使用的表名。添加到User模型中的role_id列被定义为外键,就是这个外键建立了关系。传给db.ForeignKey()的参数‘role.id’表明,这列的值是roles表中的行的id值。
添加到Role模型中的users属性代表这个关系的面向对象视角。对于一个Role类的实例,其users属性将返回与角色相关联的用户组成的列表。db.relationship()的第一个参数表明这个关系的另一端是那个模型。
db.relationship()中的backref参数向User模型中添加一个role模型,从而定义反向关系。这一属性可替代role_id访问Role模型,此时获取的是模型对象,而不是外键的值。
db.relationship()表示一对一关系时,把uselist设置为False,把多变成一
接下来在flask-script中操作数据库
python hello.py shell
创建表
from hello import db
db.create_all()
db.drop_all()
db.create_all()
插入行
from hello import Role, User
admin_role = Role(name='Admin')
mod_role = Role(name='Moderator')
user_role = Role(name='User')
user_john = User(username='john', role=admin_role)
user_susan = User(username='susan', role=user_role)
user_david = User(username='david', role=user_role)
db.session.add(admin_role)
或者可以批量添加到会话中
db.session.add_all([admin_role,mod_role,...,user_david])
提交给数据库
db.session.commit()
修改行
admin_role.name = 'test'
db.session.add(admin_role)
db.session.commit()
删除行
db.session.delete(mod_role)
db.session.commit()
查询行
User.query.filter_by(role=user_role).all()
user_role = Role.query.filter_by(name='User').first()
常用的SQLALchemy查询过滤器
过滤器 | 说明 |
---|---|
filter() | 把过滤器添加到原查询上 |
filter_by() | 把等值过滤器添加到原查询上 |
limit() | 限制原查询返回的结果数量 |
offset() | 偏移原始查询返回的结果 |
order_by() | 根据指定条件对原查询进行排序 |
group_by() | 根据指定条件对原查询结果进行分组 |
在users = db.relationship('User', backref='role', lazy='dynamic')
加入了lazy=’dynamic’参数,从而禁止自动执行查询,user_role.users会返回一个尚未执行的查询,因此可以在其上添加过滤器
user_role.users.order_by(User.username).all()
Flask-SQLAlchemy要求每个模型都要定义主键,这一列经常命名为id
最常用的SQLALCHEMY列选项
选项名 | 说明 |
---|---|
primary_key | 主键 |
unique | 是否允许重复值 |
index | 设为True,为这一 列建立索引 |
nullable | 设为True,允许使用空 |
default | 默认值 |
集成Python Shell
每次启动Shell会话都要导入数据库实例和模型,可以配置让Flask-script的shell命令自动导入特定的对象
from flask_script import Shell
def make_shell_context():
return dict(app=app, db=db, User=User, Role=Role)
manager.add_command("shell", Shell(make_context=make_shell_context))
再次执行 python hello.py shell
>>> db
'sqlite:///C:\\Users\\yuchuan\\PycharmProjects\\flasky\\data.sqlite'>
>>> app
'hello'>
>>> User
<class '__main__.User'>
在视图函数中操作数据库
@app.route('/', methods=['GET', 'POST'])
def index():
form = NameForm()
if form.validate_on_submit():
#从数据库中查询是否存在
user = User.query.filter_by(username=form.name.data).first()
if user is None:
user = User(username=form.name.data)
db.session.add(user)
session['known']=False
else:
session['known']=True
session['name']=form.name.data
form.name.data = ''
return redirect(url_for('index'))
return render_template('index.html', form=form, known=session.get('known', False), name=session.get('name'))
index.html
{% block page_content %}
<div class="page-header">
<h1>Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!h1>
{% if not known %}
<p>Pleased to meet you !p>
{% else %}
<p>Happy to see you again!p>
{% endif %}
div>
{{ wtf.quick_form(form) }}
{% endblock %}
本文参考《Flask Web开发-基于Python的Web应用开发实战》