1. from flask.ext.sqlalchemy impot SQLAlchemy
在Python2
中应该是 from flask.ext.sqlalchemy impot SQLAlchemy
但在新版的《Flask Web开发》中,书中的代码都已经使用Python3
了。虽然在Python3
中这样使用其实不会出错。但是Python3
中并不建议这样使用。未来更有可能会取消flask.ext.sqlalchemy
。
所以,在Python3
中建议使用from flask_sqlalchemy import SQLAlchemy
2. 设置SQLALCHEMY_TRACK_MODIFICATIONS 为True或False
第一次使用这个模块并运行时,会有以下的错误:
lib\site-packages\flask_sqlalchemy\__init__.py:794: FSADeprecationWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True or False to suppress this warning.
'SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and '
提示我们需要设定参数True
或者 Flase
是说SQLALCHEMY_TRACK_MODIFICATIONS
不能默认什么都没有,
得设置其为 True
或者False
解决方案:
配置文件增加以下内容:(config.py
)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
3. 数据库的操作
在Windows平台激活虚拟环境后,使用下面代码让Flask-SQLAlchemy创建数据库:
(venv) PS E:\Flasky> python
Python 3.6.4 |Anaconda, Inc.|
Type "help", "copyright", "credits" or "license" for more information.
>>> from Flask import db
>>> db.create_all()
>>> from Flask import Role,User
>>> admin_role = Role(name = 'Admin')
>>> mod_role = Role(name = 'Moderator')
>>> user_role = Role(name = 'User')
4. 数据库查询行
如果退出了shell会话,上面例子中创建的对象就不会以Python对象的形式存在,而是作为各自数据库表中的行。如果你打开了一个新的shell会话,就要从数据库中读取行,再重新创建python对象,下面发起一个查询,并加载名为User的用户角色:
(tenv) PS E:\Flasky_test> python
>>> from Flask import db
>>> from Flask import Role,User
>>> user_role = Role.query.filter_by(name = 'User').first()
>>> user_role
<Role 'User'>
下面的例子分别从关系的两端查询角色和用户之间的一对多关系:
>>> users = user_role.users
>>> users
>>> users[0].role
这个例子中的user_role.users查询有个小问题。执行 user_role.users表达式时,隐含的查询会调用all() 返回一个用户列表。query对象是隐藏的,因此无法指定更精确的查询 过滤器。就这个特定示例而言,返回一个按照字母顺序排序的用户列表可能更好。在下面的例子中,我们修改了关系的设置,加入了 lazy = 'dynamic' 参数,从而禁止自动执行查询。
修改hello.py:
class Role(db.Model):
# ...
users = db.relationship('User', backref='role', lazy='dynamic')
# ...
这样配置好关系后,user_role.users会返回一个尚未执行的查询,因此可以在其上添加过滤器:
>>> user_role.users.order_by(User.username).all()
[<User 'david'>, <User 'susan'>]
>>> user_role.users.count()
2
5. 集成Python Shell
每次启动shell都要导入数据库实例和模型,为了避免一直重复导入,我们可以让flask-script的shell命令自动导入特定的对象。
若要把对象添加到导入列表中,我们要为shell命令注册一个make_context回调函数
修改hello.py:
from flask_script import Manager, 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))
make_shell_context()
函数注册了程序、数据库实例以及模型,因此这些对象能直接导入shell:
$ python hello.py shell
>>> app
<Flask 'hello'>
>>> db
<SQLAlchemy engine='sqlite:////Users/\lovehxy/Desktop/flask study/data.sqlite'>
>>> User
<class 'main.User'>
下面完整的代码
import os
from datetime import datetime
from flask import Flask,render_template,session,redirect,url_for,flash
from flask_bootstrap import Bootstrap
from flask_moment import Moment
from flask_wtf import FlaskForm
from wtforms import StringField,SubmitField
from wtforms.validators import DataRequired
from flask_sqlalchemy import SQLAlchemy
from flask_script import Manager,Shell
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
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
bootstrap = Bootstrap(app)
moment = Moment(app)
db = SQLAlchemy(app)
manager = Manager(app)
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 '<Role %r>' % 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 '<User %r>' % self.username
class NameForm(FlaskForm):
name = StringField('What is your name?',validators=[DataRequired()])
submit = SubmitField('Submit')
def make_shell_context():
return dict(app=app, db=db, User=User, Role=Role)
manager.add_command("shell", Shell(make_context=make_shell_context))
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'),404
@app.errorhandler(500)
def internal_server_error(e):
return render_template('500.html'),500
@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,name = session.get('name'),known = session.get('know',False))
if __name__ == '__main__':
manager.run()
manager = Manager(app)
与if __name__ == '__main__': manager.run()
这两个要写上,不然Python hello.py shell 无法进入 shell。
网友评论