数据库的设置
Web应用中普遍使用的是关系模型的数据库,关系型数据库把所有的数据都存储在表中,表用来给应用的实体建模,表的列数是固定的,行数是可变的。它使用结构化的查询语言。关系型数据库的列定义了表中表示的实体的数据属性。比如:商品表里有name、price、number等。 Flask本身不限定数据库的选择,你可以选择SQL或NOSQL的任何一种。也可以选择更方便的SQLALchemy,类似于Django的ORM。SQLALchemy实际上是对数据库的抽象,让开发者不用直接和数据库打交道,而是通过Python对象来操作数据库,在舍弃一些性能开销的同时,换来的是开发效率的较大提升。
SQLALchemy是一个关系型数据库框架,它提供了高层的ORM和底层的原生数据库的操作。flask-sqlalchemy是一个简化了SQLALchemy操作的flask扩展。
安装
pip install flask-sqlalchemy
使用Flask-SQLAlchemy管理数据库
在Flask-SQLAlchemy中,数据库使用URL指定,而且程序使用的数据库必须保存到Flask配置对象的SQLALCHEMY_DATABASE_URI键中。
对比下Django和Flask中的数据库设置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'dailyfresh',
'HOST':'localhost',
'PORT':'3306',
'USER':'root',
'PASSWORD':'mysql',
}
}
Flask的数据库设置:
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test3'
常用的SQLAlchemy字段类型
常用的SQLAlchemy列选项
常用的SQLAlchemy关系选项
定义模型
模型表示程序使用的数据实体,使用SQLAlchemy中,模型一般是Python类,必须继承自db.Model,db是SQLAlchemy类的实例,代表程序使用的数据库。
类中的属性对应数据库表中的列。id为主键,是由Flask-SQLAlchemy管理。db.Column类构造函数的第一个参数是数据库列和模型属性类型。
#coding=utf-8
from flask import Flask,render_template,redirect,url_for
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test1'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
#实例化SQLAlchemy对象
db = SQLAlchemy(app)
#定义模型类-作者
class Author(db.Model):
__tablename__ = 'author'
id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(32),unique=True)
email = db.Column(db.String(64))
au_book = db.relationship('Book',backref='author')
def __str__(self):
return 'Author:%s' %self.name
#定义模型类-书名
class Book(db.Model):
__tablename__ = 'books'
id = db.Column(db.Integer,primary_key=True)
info = db.Column(db.String(32),unique=True)
lead = db.Column(db.String(32))
au_book = db.Column(db.Integer,db.ForeignKey('author.id'))
def __str__(self):
return 'Book:%s,%s'%(self.info,self.lead)
#默认访问首页查询所有作者和书名
@app.route('/')
def index():
author = Author.query.all()
book = Book.query.all()
return render_template('index.html',author=author,book=book)
#添加作者
@app.route('/append_author')
def append():
au_di = Author(name='帝国上将',email='diguo@163.com')
db.session.add(au_di)
db.session.commit()
return redirect(url_for('index'))
#添加书名
@app.route('/append_book')
def append_book():
bk_di = Book(info='仙佛录',lead='杨天行')
db.session.add(bk_di)
db.session.commit()
return redirect(url_for('index'))
#删除作者
@app.route('/delete_author<int:id>')
def delete_author(id):
db1 = Author.query.filter_by(id=id).first()
db.session.delete(db1)
return redirect(url_for('index'))
#删除书名
@app.route('/delete_book<int:id>')
def delete_book(id):
db1 = Book.query.filter_by(id=id).first()
db.session.delete(db1)
return redirect(url_for('index'))
if __name__ == '__main__':
db.drop_all()
db.create_all()
#生成数据
au_xi = Author(name='我吃西红柿',email='xihongshi@163.com')
au_qian = Author(name='萧潜',email='xiaoqian@126.com')
au_san = Author(name='唐家三少',email='sanshao@163.com')
bk_xi = Book(info='吞噬星空',lead='罗峰')
bk_xi2 = Book(info='寸芒',lead='李杨')
bk_qian = Book(info='飘渺之旅',lead='李强')
bk_san = Book(info='冰火魔厨',lead='融念冰')
#把数据提交给用户会话
db.session.add_all([au_xi,au_qian,au_san,bk_xi,bk_xi2,bk_qian,bk_san])
#提交会话
db.session.commit()
app.run(debug=True)
模板页面示例:
<h1>玄幻系列</h1>
<a href="/append_author">增加作者</a>
<ul>
<li>{% for x in author %}</li>
<li>{{ x }}</li><a href="/delete_author{{ x.id }}">删除</a>
<li>{% endfor %}</li>
</ul>
<hr>
<a href="/append_book">增加书籍</a>
<ul>
<li>{% for y in book %}</li>
<li>{{ y }}</li><a href="/delete_book{{ y.id }}">删除</a>
<li>{% endfor %}</li>
</ul>
数据库基本操作
在Flask-SQLAlchemy中,插入、修改、删除操作,均由数据库会话管理。会话用db.session表示。在准备把数据写入数据库前,要先将数据添加到会话中然后调用commit()方法提交会话。
在Flask-SQLAlchemy中,查询操作是通过query对象操作数据。最基本的查询是返回表中所有数据,可以通过过滤器进行更精确的数据库查询。
将数据添加到会话中示例:
user = User(name='python')
db.session.add(user)
db.session.commit()
在视图函数中定义模型类
#coding=utf-8
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
#设置连接数据库的URL
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/Flask_test'
#设置每次请求结束后会自动提交数据库中的改动
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
class Role(db.Model):
# 定义表名
__tablename__ = 'roles'
# 定义列对象
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
user = db.relationship('User', backref='role')
#repr()方法显示一个可读字符串
def __repr__(self):
return 'Role:'.format(self.name)
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True, index=True)
pswd = db.Column(db.String(64))
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
def __repr__(self):
return 'User:'.format(self.username)
if __name__ == '__main__':
db.drop_all()
db.create_all()
常用的SQLAlchemy查询过滤器
常用的SQLAlchemy查询执行器
创建表:
db.create_all()
删除表
db.drop_all()
插入一条数据
In [7]: us = User(name='wang',email='wang@163.com',pswd='123456')
In [8]: db.session.add(us)
In [9]: db.session.commit()
插入多条数据
In [14]: us2 = User(name='zhang',email='zhang@163.com',pswd='201512')
In [15]: us3 = User(name='chen',email='chen@163.com',pswd='987654')
In [16]: us4 = User(name='zhou',email='zhou@163.com',pswd='456789')
In [17]: db.session.add_all([us2,us3,us4])
In [18]: db.session.commit()
查询:filter_by精确查询
返回名字等于wang的所有人
user = User.query.filter_by(name='wang').all()
print user
print user.id
first()返回查询到的第一个对象
user = User.query.first()
print user
all()返回查询到的所有对象
User.query.all()
filter模糊查询,返回名字结尾字符为e的所有数据。
User.query.filter(User.name.endswith('e')).all()
get(),参数为主键,如果主键不存在没有返回内容
User.query.get()
逻辑非,返回名字不等于zhou的所有数据。
user = User.query.filter(User.name!='zhou').all()
print user
逻辑与,需要导入and,返回and()条件满足的所有数据。
from sqlalchemy import and_
user = User.query.filter(and_(User.name!='wang',User.email.endswith('163.com'))).all()
print user
逻辑或,需要导入or_
from sqlalchemy import or_
user = User.query.filter(or_(User.name!='wang',User.email.endswith('163.com'))).first()
print user
not_ 相当于取反
from sqlalchemy import not_
user = User.query.filter(not_(User.name=='wang')).all()
print user
查询数据后删除
user = User.query.first()
db.session.delete(user)
db.session.commit()
User.query.all()
更新数据
user = User.query.first()
user.name = 'dong'
db.session.commit()
User.query.first()
数据库迁移
在开发过程中,需要修改数据库模型,而且还要在修改之后更新数据库。最直接的方式就是删除旧表,但这样会丢失数据。
更好的解决办法是使用数据库迁移框架,它可以追踪数据库模式的变化,然后把变动应用到数据库中。
在Flask中可以使用Flask-Migrate扩展,来实现数据迁移。并且集成到Flask-Script中,所有操作通过命令就能完成。
为了导出数据库迁移命令,Flask-Migrate提供了一个MigrateCommand类,可以附加到flask-script的manager对象上。
首先要在虚拟环境中安装Flask-Migrate。
pip install flask-migrate
创建迁移仓库
#这个命令会创建migrations文件夹,所有迁移文件都放在里面。
python database.py db init
创建迁移脚本
自动创建迁移脚本有两个函数,upgrade()函数把迁移中的改动应用到数据库中。downgrade()函数则将改动删除。自动创建的迁移脚本会根据模型定义和数据库当前状态的差异,生成upgrade()和downgrade()函数的内容。对比不一定完全正确,有可能会遗漏一些细节,需要进行检查
#创建自动迁移脚本
python database.py db migrate -m 'initial migration'
更新数据库
python database.py db upgrade
#coding=utf-8
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate,MigrateCommand
from flask_script import Shell,Manager
app = Flask(__name__)
manager = Manager(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/Flask_test'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
migrate = Migrate(app,db)
manager.add_command('db',MigrateCommand)
#定义模型Role
class Role(db.Model):
# 定义表名
__tablename__ = 'roles'
# 定义列对象
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
user = db.relationship('User', backref='role')
#repr()方法显示一个可读字符串,
def __repr__(self):
return 'Role:'.format(self.name)
#定义用户
class User(db.Model):
__talbe__ = '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 'User:'.format(self.username)
if __name__ == '__main__':
#创建表
db.create_all()
#给Role模型添加数据
admin_role = Role(name='Administer')
user_role = Role(name='User')
#给User模型添加数据
user_zhangsan = User(username='zhangsan', role=admin_role)
user_lisi = User(username='lisi', role=user_role)
user_wangwu = User(username='wangwu', role=user_role)
user_zhaoliu = User(username='zhaoliu', role=user_role)
#提交数据
db.session.add_all([admin_role,user_role, user_zhangsan, user_lisi, user_wangwu, user_zhaoliu])
db.session.commit()
manager.run()
Flask—Mail
在开发过程中,很多应用程序都需要通过邮件提醒用户,Flask的扩展包Flask-Mail通过包装了Python内置的smtplib包,可以用在Flask程序中发送邮件。
Flask-Mail连接到简单邮件协议(Simple Mail Transfer Protocol,SMTP)服务器,并把邮件交给服务器发送。
如下示例,通过开启QQ邮箱SMTP服务设置,发送邮件。
from flask import Flask
from flask_mail import Mail, Message
app = Flask(__name__)
#配置邮件:服务器/端口/传输层安全协议/邮箱名/密码
app.config.update(
DEBUG = True,
MAIL_SERVER='smtp.qq.com',
MAIL_PROT=465,
MAIL_USE_TLS = True,
MAIL_USERNAME = '371673381@qq.com',
MAIL_PASSWORD = 'goyubxohbtzfbidd',
)
mail = Mail(app)
@app.route('/')
def index():
# sender 发送方,recipients 接收方列表
msg = Message("This is a test ",sender='371673381@qq.com', recipients=['shengjun@itcast.cn','371673381@qq.com'])
#邮件内容
msg.body = "Flask test mail"
#发送邮件
mail.send(msg)
print "Mail sent"
return "Sent Succeed"
if __name__ == "__main__":
app.run()