chapter5 - Web数据库

5.1 Python数据库框架

Flask允许自己选择需要的数据库框架,但在选择时,应考虑这些因素:

  • 易用性 这里要注重的两个概念是ORM或ODM,也就是对象关系映射和对象文档映射。它们用于把高层的面向对象操作转换成低层的数据库指令。
  • 性能
  • 可移植性 是否可在多个平台中平移
  • Flask集成度 使用集成了Flask的框架可以简化配置和操作

因此本书选择的是Flask-SQLAlchemy,这个Flask扩展包装了SQLAlchemy框架

5.2 使用Flask-SQLAlchemy管理数据库

安装

可使用pip安装:(venv) $ pip install flask-sqlalchemy。在Flask-SQLAlchemy中,数据库使用URL指定,也就是以URL的形式来连接数据库,而不是sql原生的connect之类的操作。具体格式如下表:

数据库引擎 URL MySQL mysql://username:password@hostname/database Postgres postgresql://user SQLite (Unix) sqlite:////absolute/path/to/database SQLite (Windows) sqlite:///c:/absolute/path/to/database

hostname表示MySQL服务所在的主机,可以是本地主机或远程服务器 database表示要使用的数据库名称 username和password表示需要有到的数据库用户密令

本书使用的是SQLite数据库,它不需要服务器,因此URL中的database是硬盘上的文件名

配置数据库

程序使用的数据库URL必须保存到Flask配置对象的SQLALCHEMY_DATABASE_URI中,另外还有个要设置的是SQLALCHEMY_COMMIT_ON_TEARDOWN键,将其设为True时,每次执行SQL请求后会自动提交。

经个人实测发现,如果仅做了以上两个设置,在运行时会有警告:

/home/cavin/Code/Python/flask/lib64/python3.5/site-packages/flask_sqlalchemy/__init__.py:800: UserWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.
  warnings.warn('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.')

按提示说的,把这个变量配置成True即可消除这个警告:

app.config[SQLACHEMY_TRACK_MODIFICANTS'] = True

因此,配置后的hello.py文件为:

from flask_sqlalchemy import SQLAlchemy

basedir = os.path.abspath(os.path.dirname(__file__))

app = Flask(__name__)
app.config[SQLALCHEMY_DATABASE_URI'] = sqlite:///' + os.path.join(basedir,data.sqlite'SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config[SQLALCHEMY_TRACK_MODIFICANTS True

db = SQLAlchemy(app)

注意以上(除了app = Flask(__name__))外都是新添加到文件中的内容,其它内容不变basedir变量可以获取当前文件的绝对路径。

db是SQLAlchemy类的一个实例,表示程序使用的数据库,同时也获得了Flask-SQLAlchemy提供的所有功能。

5.3 定义模型

其实这里所说到的“模型”,在某种程度上可看做是传统SQL中的“数据表”。如下可定义Role和User模型:

class Role(db.Model):
    __tablename__ = roles
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(64),unique=True)

    def __repr__(self):
        return <Role %r>' % self.name

 User(db.Model):
    users True)
    username = db.Column(db.String(64),unique=True,index=<User %r>' % self.username

其中,__tablename__定义了在数据库中使用的表名。其余的id、name、username这些都是模型的属性,相当于数据表中的字段,用db.Column构造函数实现,其第一个参数是数据库列和模型属性的类型。

模型中的__repr()__方法并不是强制要求的,这里定义了并返回一个具有可读性的字符串表示模型,可方便调试和测试。 常用的SQLAlchemy列类型如下:

类型名 Python类型 说明 Integer int 普通整数,一般是32位 SmallInteger int 取值范围小的整数,一般是16位 BigInteger int或long 不限制精度的整数 Float float 浮点数 Numeric decimal.Decimal 定点数 String str 变长字符串 Text str 变长字符串,对较长或不限长度的字符串做了优化 Unicode unicode 变长Unicode字符串 UnicodeText unicode 变长Unicode字符串,对较长或不限长度的字符串做了优化 Boolean bool 布尔值 Date datetime.date 日期 Time datetime.time 时间 DateTime datetime.datetime 日期和时间 Interval datetime.timedelta 时间间隔 Enum str 一组字符串 PickleType 任何Python对象 自动使用Pickle序列化 LargeBinary str 二进制文件

db.Column中其余的参数指定属性的配置选项,常用的可选项如下:

选项名 说明 primary_key 如果设置为True,这列就是表的主键 unique 如果设置为True,这列不允许出现复生值 index 如果设置为True,为这列创建索引 nullable 如果设置为True,这列允许为空;为False则不允许空 default 为这列定义默认值

Flask-SQLAlchemy要求每个模型都要定义主键,通常命名为id

5.4 关系

关系也即不同表之间的联系。例如,一个论坛中的用户有其自己的id,其归属于一个分组,这个组也有组的id,用户信息表和分组表可以通这两个各自的id来关联起来。一个组可以有多个用户,但一个用户同时只能归属于一个组。这就是一对多的关系。 在模型中表示如下: 修改hello.py

 Role(db.Model):
    # 之前的内容
    users = db.relationship(User',backref=role)

 User(db.Model):
     之前的内容
    role_id = db.Column(db.Integer,db.ForeignKey(roles.id'))

User模型中的role_id表被定义为外键,建立起了关系,传给db.ForeignKey()的参数roles.id表明,这列的值是roles表中的id值。

在Role模型中,users属性返回与角色相关联的用户组成的列表,db.relationship()的第一个参数表明这个关系连接的是哪一个表。第二个参数backref向User模型添加了一个role属性,定义了反向关系。 定义关系时(db.relationship())常用的配置选项有:

选项名 说明 backref 在关系的另一个模型中添加反向引用 primaryjoin 明确指定两个模型之间使用的联结条件 lazy 指定如何加载相关记录。

可选值有select-首次访问时按需加载;immediate-源对象加载后就加载;joined-加载记录,但使用联结;subquery-立即加载,但使用子查询;noload-永不加载、dynamic-不加载记录,但提供加载记录的查询 uselist 如果设为False,不使用列表,而使用标量值 order_by 指定关系中记录的排序方式 secondary 指定多对多关系中关系表的名字 secondaryjoin SQLAlchemy无法自行决定时,指定多对多关系中的二级联结条件、

5.5 数据库操作

5.5.1 创建表

(venv) $ python hello.py shell
>>> from hello  db
>>> db.create_all()

此时,就可在程序目录中新建了一个名为data.sqlite的文件。

5.5.2 插入数据

>>>  Role,User
>>> admin_role = Role(name=Admin)
>>> mod_role = Role(name=Moderator)
>>> user_role = Role(name=)
>>> user_john = User(username=johnadmin_role)
>>> user_susan = User(username=susanuser_role)
>>> user_david = User(username=david
>>> db.session.add(admin_role)
>>> db.session.add(mod_role)
>>> db.session.add(user_role)
>>> db.session.add(user_john)
>>> db.session.add(user_susan)
>>> db.session.add(user_david)

或简写方式:

>>> db.session.add_all([admin_role,mod_role,user_role,user_john,user_susan,user_david])

写入数据库:

>>> db.session.commit()

应注意的是,这里的数据库会话db.session和第4章中提到的Flask session对象没有关系,它只是数据库会话,或称为事务。数据库会话可以保持数据库操作的一致性。 当然,它也有回滚:db.session.rollback()

 

 

5.6 使用Flask-Migrate实现数据库迁移

所谓数据库迁移,其实主要是数据库(包含其结构与字段属性等)的更新。比如说新增了表、字段等。使用Flask-Migrate可以很好地实现数据库平移更新,不改变原有结构和数据,也不需要删除重建。

5.6.1 创建迁移仓库

先要安装Flask-Migrate:

(venv) $ pip install flask-migrate

在程序入口文件hello.py中增加对数据库迁移的支持:

from flask_migrate  Migrate,MigrateCommand

 .其它原有代码

migrate = Migrate(app,db)
manager.add_command(db,MigrateCommand)

 其它代码

然后才是使用init子命令来创建迁移仓库:

(venv) $ python hello.py db init

这个命令会创建migrations文件夹,所有的迁移脚本都会放在里面

5.6.2 创建迁移脚本

(venv) $ python hello.py db migrate -m "initial migration"

5.6.3 更新数据库

(venv) $ python hello.py db update

这里应该要提出的是,在本书后面,作者在需要进行更新数据库的时候,只会提到需要读者执行更新数据库的命令:python hello.py update,却没有说到需要执行创建迁移脚本命令。这是因为作者默认读者是从本书的github仓库上pull代码的,而pull下来的代码里面已经包含有数据库迁移脚本了,所以不需要再创建。如果是自己更新代码而不是从github上下载代码的话,那么就必须要先执行创建迁移脚本的命令,然后再执行更新数据库的命令才会有效。切记!

原文地址:https://www.cnblogs.com/tracydzf

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Jinja2:是Python的Web项目中被广泛应用的模板引擎,是由Python实现的模板语言,Jinja2 的作者也是 Flask 的作者。他的设计思想来源于Django的模板引擎,并扩展了其语法和一系列强大的功能,其是Flask内置的模板语言。
Fullcalendar日历使用,包括视图选择、事件插入、编辑事件、事件状态更改、事件添加和删除、事件拖动调整,自定义头部,加入el-popover显示图片、图片预览、添加附件链接等,支持手机显示。
监听QQ消息并不需要我们写代码,因为市面上已经有很多开源QQ机器人框架,在这里我们使用go-cqhttp官方文档:go-cqhttp如果您感兴趣的话,可以阅读一下官方文档,如果不想看,直接看我的文章即可。
【Flask框架】—— 视图和URL总结
python+web+flask轻量级框架的实战小项目。登录功能,后续功能可自行丰富。
有了这个就可以配置可信IP,关键是不需要企业认证,个人信息就可以做。
本专栏是对Flask官方文档中个人博客搭建进行的归纳总结,与官方文档结合事半功倍。 本人经验,学习一门语言或框架时,请首先阅读官方文档。学习完毕后,再看其他相关文章(如本系列文章),才是正确的学习道路。
本专栏是对Flask官方文档中个人博客搭建进行的归纳总结,与官方文档结合事半功倍。基础薄弱的同学请戳Flask官方文档教程 本人经验,学习一门语言或框架时,请首先阅读官方文档。学习完毕后,再看其他相关文章(如本系列文章),才是正确的学习道路。 如果python都完全不熟悉,一定不要着急学习框架,请首先学习python官方文档,一步一个脚印。要不然从入门到放弃是大概率事件。 Python 官方文档教程
快到年末了 相信大家都在忙着处理年末数据 刚好有一个是对超市的商品库存进行分析的学员案例 真的非常简单~
一个简易的问答系统就这样完成了,当然,这个项目还可以进一步完善,比如 将数据存入Elasticsearch,通过它先进行初步的检索,然后再通过这个系统,当然我们也可以用其他的架构实现。如果你对这系统还有其他的疑问,也可以再下面进行留言!!!
#模版继承和页面之间的调用@app.route(&quot;/bl&quot;)def bl(): return render_template(&quot;file_2.html&quot;)主ht
#form表达提交@app.route(&quot;/data&quot;,methods=[&#39;GET&#39;,&#39;POST&#39;]) #methods 让当前路由支持GET 和
#form表达提交@app.route(&quot;/data&quot;,methods=[&#39;GET&#39;,&#39;POST&#39;]) #methods 让当前路由支持GET 和
#session 使用app.secret_key = &quot;dsada12212132dsad1232113&quot;app.config[&#39;PERMANENT_SESSION_LI
#文件上传@app.route(&quot;/file&quot;,methods=[&#39;GET&#39;,&#39;POST&#39;])def file(): if request.meth
#跳转操作:redirect@app.route(&quot;/red&quot;)def red(): return redirect(&quot;/login&quot;)
#session 使用app.secret_key = &quot;dsada12212132dsad1232113&quot;app.config[&#39;PERMANENT_SESSION_LI
@app.route(&quot;/req&quot;,methods=[&#39;GET&#39;,&#39;POST&#39;])def req(): print(request.headers)
#模版继承和页面之间的调用@app.route(&quot;/bl&quot;)def bl(): return render_template(&quot;file_2.html&quot;)主ht
#文件操作:send_file,支持图片 视频 mp3 文本等@app.route(&quot;/img&quot;)def img(): return send_file(&quot;1.jpg&q