Flask-SQLALchemy 

Flask-SQLALchemy 是一个给你的应用添加 SQLALchemy 支持的 Flask 扩展。

它需要 SQLAlchemy 0.6 或更高的版本。它致力于简化在 Flask 中 SQLAlchemy 的 使用,提供了有用的默认值和额外的助手来更简单地完成日常任务。

我的conda源没有,我就直接pip3

第六章 Flask数据库(二)

 第六章 Flask数据库(二)

 

数据库连接:

1. 与sqlalchemy一样,定义好数据库连接字符串DB_URI。
2. 将这个定义好的数据库连接字符串DB_URI,通过SQLALCHEMY_DATABASE_URI这个键放到app.config中。示例代码:app.config["SQLALCHEMY_DATABASE_URI"] = DB_URI.
3. 使用flask_sqlalchemy.SQLAlchemy类定义一个对象,并将app传入进去。示例代码:db = SQLAlchemy(app)。

创建ORM模型:

1. 与使用sqlalchemy一样,定义模型。现在不需要使用delarative_base来创建一个基类,而是使用db.Model来作为基类。
2. 在模型类中,Column、String、Integer以及relationship等,都不需要导入了,直接使用db下面相应的属性名就可以了。
3. 在定义模型的时候,可以不写__tablename__,那么flask_sqlalchemy会默认使用如果不设置该属性,类名小写作表名,
并且如果这个模型的名字使用多个单词且是驼峰命名法,则多个单词之间使用下划线来进行连接。

将ORM模型映射到数据库:

1. db.drop_all()
2. db.create_all()

使用session:

session也不需要使用sessionmaker来创建了。直接使用db.session且操作方式与SQLAl相同

查询数据:

如果查找数据只是查找一个模型上的数据,可以直接通过模型.query的方式进行查找。query就跟之前的sqlalchemy中的query方法是一样用的。

 

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'flask_sqlalchemy'
USERNAME = 'root'
PASSWORD = 'root'

# dialect+driver://username:password@host:port/database
DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)

app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)

# 明言胜于暗喻

class User(db.Model):
    #__tablename__ = 'user' 如果不设置该属性,类名小写作表名
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    username = db.Column(db.String(50),nullable=False)

    def __repr__(self):
        return "<User(username: %s)>" % self.username

class Article(db.Model):
    __tablename__ = 'article'
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    title = db.Column(db.String(50),nullable=False)
    uid = db.Column(db.Integer,db.ForeignKey("user.id"))

    author = db.relationship("User",backref="artiles")

db.drop_all()
db.create_all()

user = User(username='wqbin')
article = Article(title='title one')
sess=db.session

article.author = user
sess.add(article)

sess.commit()

users = User.query.order_by(User.id.desc()).all()
print(users)

user = User.query.filter(User.username=='wqbin').first()
user.username='wqbin1'

sess.commit()


@app.route('/')
def hello_world():
    return 'Hello World!'


if __name__ == '__main__':
    app.run()

 

alembic 

SQLAlchemy该ORM框架本身没有带数据库版本控制功能,但是进行开发过程中难免修改数据模型,添加表,修改字段,都需要手动修改。于是两个解决该缺陷的两个工具应运而生,alembic与SQLAlchemy-Migrate。

alembic是sqlalchemy的作者开发的,Alembic 使用 SQLAlchemy 作为数据库引擎,为关系型数据提供创建、管理、更改和调用的管理脚本,协助开发和运维人员在系统上线后对数据库进行在线管理,主要用来做ORM模型与数据库的迁移与映射。

alembic使用方式跟git类似,表现在两个方面

  1. alembic的所有命令都是以alembic开头;
  2. alembic的迁移文件也是通过版本进行控制的。

以下将解释alembic的用法:

  1. 初始化alembic仓库:在终端中cd到项目目录中,然后执行命令alembic init alembic,创建alembic的仓库。
  2. 创建模型类:创建一个models.py模块,然后在里面定义模型类。
  3. 修改配置文件alembic.init
  4. 修改env.py
  5. 自动生成迁移文件:使用alembic revision --autogenerate-m "message"将当前模型中的状态生成迁移文件。
  6. 更新数据库:使用alembic upgrade head将刚刚生成的迁移文件,真正映射到数据库中。同理,如果要降级,那么使用alembic downgrade head。
  1. 修改代码后,重复4~5的步骤。

细节如下:

1.alembic init alembic

第六章 Flask数据库(二)

2.alembic.init

from sqlalchemy import Column,String,Integer,create_engine
from sqlalchemy.ext.declarative import declarative_base

DB_USERNAME = 'root'
DB_PASSWORD = 'root'
DB_HOST = '127.0.0.1'
DB_PORT = '3306'
DB_NAME = 'alembic'

DB_URI = 'mysql+pymysql://%s:%s@%s:%s/%s?charset=utf8' % (DB_USERNAME,DB_PASSWORD,DB_HOST,DB_PORT,DB_NAME)

engine = create_engine(DB_URI)

Base = declarative_base(engine)

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer,primary_key=True,autoincrement=True)
    username = Column(String(50),nullable=False)
    country = Column(String(50))

3.修改配置文件alembic.init

【alembic】
 sqlalchemy.url = driver://user:pass@localhost/dbname
改成:
【alembic】
 sqlalchemy.url = mysql+pymysql://root:root@localhost/alembic?charset=utf8

4.修改env.py

from __future__ import with_statement

from logging.config import fileConfig

from sqlalchemy import engine_from_config
from sqlalchemy import pool

from alembic import context

import sys,os
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
import models
# this is the Alembic Config object, which provides access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging. This line sets up loggers basically.
fileConfig(config.config_file_name)
# add your model's MetaData object here for 'autogenerate' support from myapp import mymodel target_metadata = mymodel.Base.metadata
target_metadata = models.Base.metadata

 

第六章 Flask数据库(二)

 

 5.使用alembic revision --autogenerate-m "aessage"将当前模型中的状态生成迁移文件

第六章 Flask数据库(二)

在flask中进行数据库迁移时报错,报错信息为"Target database is not up",解决方案如下:

方法一:(网上看的没找到对应)

  1. 找到alembic(数据库中的数据表)的最新版本号,找到文件夹verisons下的最新版本,文件名即为最新版本号(去掉末尾的_)。
  2. 然后更新数据库表alembic_version里version_num的字段,将该字段的值改为最新版本号
  3. 再次迁移即可成功

方法二:

  1.  删除数据库表alembic_version表和versions下面所有版本文件
  2.  重新输入revision命令

第六章 Flask数据库(二)

第六章 Flask数据库(二)

第六章 Flask数据库(二)

 第六章 Flask数据库(二)

 message.py文件内容:

第六章 Flask数据库(二)

 5.更新数据库:使用alembic upgrade head将刚刚生成的迁移文件,真正映射到数据库中

第六章 Flask数据库(二)

第六章 Flask数据库(二)

 

 6.重复:修改文件增加字段,更新数据库

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer,primary_key=True,autoincrement=True)
    username = Column(String(50),nullable=False)
    country = Column(String(50))
    city = Column(String(50))

第六章 Flask数据库(二)

 第六章 Flask数据库(二)

 第六章 Flask数据库(二)

几点补充:

PS C:\Users\WQBin\Desktop\python_flask\> alembic heads
dda532d698cb (head)
PS C:\Users\WQBin\Desktop\python_flask\> alembic upgrade 7ddd5756b83f
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
ERROR [alembic.util.messaging] Destination 7ddd5756b83f is not a valid upgrade target from current head(s)
FAILED: Destination 7ddd5756b83f is not a valid upgrade target from current head(s)

PS C:\Users\WQBin\Desktop\python_flask\> alembic downgrade dda532d698cb
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.

当head指针和current指针不对齐,不及时做upgrade 和downgrade,再做一些其他操作则会报错。

第六章 Flask数据库(二)

经典错误

1. FAILED: Target database is not up to date.
     原因:主要是heads和current不相同。current落后于heads的版本。
     解决办法:将current移动到head上。alembic upgrade head
2. FAILED: Can't locate revision identified by 'xxxxxx'
     原因:数据库中存的版本号不在迁移脚本文件中
     解决办法:删除数据库的alembic_version表中的数据,重新执行alembic upgrade head
3. 执行`upgrade head`时报某个表已经存在的错误:
     原因:执行这个命令的时候,会执行所有的迁移脚本,因为数据库中已经存在了这个表。然后迁移脚本中又包含了创建表的代码。
     解决办法:(1)删除versions中所有的迁移文件。(2)修改迁移脚本中创建表的代码

常用参数介绍:

init:创建一个alembic仓库
revision:创建一个新的版本文件
--autogenerate:自动将当前模型的修改,生成迁移脚本
-m:本次迁移做了哪些修改,用户可以指定这个参数,方便回顾
upgrade:将指定版本的迁移文件映射到数据库中,会执行版本文件中的upgrade函数。如果有多个迁移脚本没有被映射到数据库中,那么会执行多个迁移脚本
[head]:代表最新的迁移脚本的版本号
downgrade:会执行指定版本的迁移文件中的 down grade函数
heads:展示head指向的脚本文件版本号
history:列出所有的迁移版本及其信息
curent:展示当前数据库中的版本号

 

 Flask-Script:

[flask-script 不再维护了,官网推荐使用flask自带cli]

简介与安装

 Flask-Script的作用是可以通过命令行的形式来操作Flask,Flask-Script的作用从某种意义上来说是为了更好的管理项目,它通过一个manager来作为脚本控制整个项目的各个小部分点。

例如通过命令跑开发版本的服务器、设置数据库,定时任务等。  Flask-Script和Flask本身的工作方式类似,只需要定义和添加能从命令行中被Manager实例调用的命令即可。

Flask的开发Web服务器支持很多启动设置选项,但只能在脚本中作为参数传给app.run()函数。这种方式很不方便,传递设置选项的理想方式是使用命令行参数。

Flask-Scrip就是这么一个Flask扩展,为Flask程序添加一个命令行解析器。Flask-Script自带了一组常用选项,而且还支持自定义命令。

第六章 Flask数据库(二)

 

定义命令的三种方法

  • 使用@command 装饰器
  • 使用类继承自Command类
  • 使用option装饰器

1.使用@command 装饰器

把脚本命令代码放在一个叫做manage.py文件中,然后在终端运行python manage.py hello命令,就可以看到输出hello。

from flask_script import Manager
from flask_script_app import app


manager = Manager(app)

@manager.command
def greet():
    print('你好')
if __name__ == '__main__':
    manager.run()

第六章 Flask数据库(二)

2.使用类继承自Command类

      使用类的方式,有三点需要注意:

  1. 必须继承自Command基类
  2. 必须实现run方法
  3. 必须通过add_command 方法添加命令
from flask_script import Manager,Command

manager = Manager(app)
class SayHi(Command):

    def run(self):
        print('你好from [继承command的类方法]')

manager.add_command("sayhi", SayHi)

第六章 Flask数据库(二)

3.使用option装饰器:如果想要在使用命令的时候还传递参数进去,那么使用@option 装饰器更加的方便:

@manager.option("-u","--username",dest="username")
@manager.option("-e","--email",dest="email")
def add_user(username,email):
    print(username,email)

第六章 Flask数据库(二)

 

小案例:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import config

app = Flask(__name__)
app.config.from_object(config)
db = SQLAlchemy(app)

class BackendUser(db.Model):
    __tablename__ = 'backend_user'
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    username = db.Column(db.String(50),nullable=False)
    email = db.Column(db.String(50),nullable=False)

db.create_all()

@app.route('/')
def hello_world():
    return 'Hello World!'


if __name__ == '__main__':
    app.run()
flask_script_app.py

相关文章: