美文网首页
《Flask Web开发》中SQLALCHEMY出现的问题

《Flask Web开发》中SQLALCHEMY出现的问题

作者: Dozing | 来源:发表于2018-09-10 21:49 被阅读70次

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。

相关文章

网友评论

      本文标题:《Flask Web开发》中SQLALCHEMY出现的问题

      本文链接:https://www.haomeiwen.com/subject/bgfqgftx.html