Python的Flask框架与数据库连接的科目,Symfony框架中的Doctrine

场合及优势

熟习Symfony框架之后,深远感触到框架集成的ORM组件Doctrine2的强有力之处,其中附带的多少迁移也要命便宜。Doctrine2是行使Doctrine
DBAL组件把代码里面的表结构与实际数据库中的表结构进行对照的法子开展多少迁移。那种办法比此前版本管理的点子进一步精准也更便于。

Symfony框架是我ORM组件辅助,但是众八种类并没有应用其中的ORM功效,或者有投机的ORM组件,又该怎么样集成diff形式的动迁呢?上边大家就来完结那个任务。

Python的Flask框架中选拔Flask-Migrate扩张迁移数据库的学科,flaskflask-migrate

我们在进步系统的时候,日常遇上要求立异服务器端数据结构等操作,此前的主意是透过手工编写alter
sql脚本甩卖,寻常会发现遗漏,导致程序发表到服务器上后无法正常使用。

当今我们得以拔取Flask-Migrate插件来化解之,Flask-Migrate插件是基于Alembic,Alembic是由出名的SQLAlchemy小编开发数据迁移工具。

具体操作如下:

1. 安装Flask-Migrate插件

$ pip install Flask-Migrate

2. 修改Flask App部分的代码,以充实Migrate相关的Command

db = SQLAlchemy(app)
migrate = Migrate(app, db)

manager = Manager(app)
manager.add_command('db', MigrateCommand)

3. 初始化

$ python app.py db init

采纳Flask-Migrate迁移数据库
乘胜开发进度不断向前,你会意识你的数据库模型必要转移,而当这种情景暴发时必要立异数据库。

Flask-SQLAlchemy唯有当数据库表不设有了才从模型创建它们,所以更新表的唯一途径就是绝迹旧的表,当然那将造成所有数据库中的数据丢失。

有个更好的化解方案就是利用数据库迁移框架。和源码版本控制工具跟踪更改源码文件一律,数据库迁移框架跟踪更改数据库模型,然后将增量变化选用到数据库中。

SQLAlchemy的要紧开发人士写了一个Alembic迁移框架,但大家不直接行使Alembic,Flask应用可以选用Flask-Migrate扩充,一个并入了Flask-Script来提供所有操作命令的轻量级Alembic包。

4. 创建迁移仓库

率先,Flask-Migrate必须已经设置到虚拟环境中:

(venv) $ pip install flask-migrate

上边展示增加怎么着伊始化:

from flask.ext.migrate import Migrate, MigrateCommand 

# ...

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

为了可以采用数据库迁移命令,Flask-Migrate提供MigrateCommand类来连接Flask-Script的manager对象。在那些示例中应用db来再而三到命令。

在数据库迁移可以有限支持从前,必须透过init子命令来创设一个迁移库:

(venv) $ python hello.py db init

 Creating directory /home/flask/flasky/migrations...done
 Creating directory /home/flask/flasky/migrations/versions...done
 Generating /home/flask/flasky/migrations/alembic.ini...done
 Generating /home/flask/flasky/migrations/env.py...done
 Generating /home/flask/flasky/migrations/env.pyc...done
 Generating /home/flask/flasky/migrations/README...done
 Generating /home/flask/flasky/migrations/script.py.mako...done
 Please edit configuration/connection/logging settings in
 '/home/flask/flasky/migrations/alembic.ini' before proceeding.

这一个命令创设一个migrations文件夹,里面存放了有着迁移脚本。

提出:假若你有克隆在GitHub上的应用程序,你现在可以运行git checkout
5c来切换来那么些本子的应用程序。

5. 创办迁移脚本

在Alembic,数据库迁移工作由迁移脚本完毕。那么些本子有多个函数,分别叫做upgrade()和downgrade()。upgrade()函数实施数据库更改,是迁移的一有些,downgrade()函数则删除它们。通过抬高和删除数据库变化的能力,Alembic可以重新配置数据库从历史记录中的任哪天间点。

Alembic迁移可以分级采纳revision和migrate命令手动或机关创制。手动迁移通过由开发人士使用Alembic的Operations对象指令已毕的空upgrade()和downgrade()函数成立迁移框架脚本。另一方面,自动迁移通过寻找模型定义和数据库当前情况间的两样为upgrade()和downgrade()生成代码。

警告:自动迁移并不一连准确的,可以忽略一些细节。所以理应时时审查一下自动生成的迁移脚本。
migrate子命令创建机关迁移脚本:

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

INFO [alembic.migration] Context impl SQLiteImpl.
INFO [alembic.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate] Detected added table 'roles'
INFO [alembic.autogenerate] Detected added table 'users'
INFO [alembic.autogenerate.compare] Detected added index
'ix_users_username' on '['username']'
 Generating /home/flask/flasky/migrations/versions/1bc
 594146bb5_initial_migration.py...done

提议:假设您有克隆在GitHub上的应用程序,你现在得以运作git checkout
5c来切换来那些版本的应用程序。注意,你不要求为这么些动用生成migrations,所有的迁移脚本都含有在版本库中。
6. 翻新数据库

若果迁移脚本被审查且接受,就足以选拔db upgrade命令更新到数据库中:

(venv) $ python hello.py db upgrade

INFO [alembic.migration] Context impl SQLiteImpl.
INFO [alembic.migration] Will assume non-transactional DDL.
INFO [alembic.migration] Running upgrade None -> 1bc594146bb5, initial migration

第二回迁移实际上相当于调用db.create_all(),但在接二连三迁移中,upgrade命令对表实施立异操作但不影响表中的内容。

我们在进步系统的时候,平常境遇必要立异服务器端数据结构等操作…

在新的标准版本的Symfony框架中已经合龙了Doctrine,Doctrine就是一种对象关系映射(ORM)同时也是一种数据库抽象层(DBAL),使用ORM和DBAL能让大家很自由的操作数据库。本作品首要在于在Symfony中利用Doctrine——怎样创设数量库表的模子,怎么样创制表的涉及,怎么查询数据等等。

 命令行方式运行Python脚本

源码解析

在商量组件源码时,发现一个类:Doctrine\DBAL\Migrations\Provider\SchemaDiffProvider澳门葡京备用网址,,其中getSqlDiffToMigrate格局就是我们编辑diff脚本的首要。

/**
 * @param Schema $fromSchema
 * @param Schema $toSchema
 * @return string[]
 */
public function getSqlDiffToMigrate(Schema $fromSchema, Schema $toSchema)
{
    return $fromSchema->getMigrateToSql($toSchema, $this->platform);
}

该办法通过传播的三个入参(fromSchema和toSchema),来对待旧数据结构和新数据结构的差别,最终回来相关的sql语句。那么大家只要得到存活数据库中的表结构,以及代码里面的表结构,就能促成diff格局的数额迁移了。

取得现有数据库的表结构得以由此地方的createFromSchema措施直接获得。

然后大家必要把数据结构写入代码,再从代码中拿走实时的表结构,最后diff。

开创和配备数据库

 Doctrine Configuration
doctrine:
    dbal:
        driver:   pdo_mysql
        host:     "%database_host%"
        port:     "%database_port%"
        dbname:   "%database_name%"
        user:     "%database_user%"
        password: "%database_password%"
        charset:  utf8mb4
        collate: utf8mb4_unicode_ci 

Doctrine作为PDO的顶层可以操作任何支持PDO的数据库操作系统(比如MySQL,PostgreSQL,Microsoft
SQL,MongoDB和玛丽亚DB)。那里推荐设置默许的数据库字符集和排序集为utf8mb4。有别于老的utf8字符集,utf8mb4支撑4字节的Unicode编码。数据库的主机地址、端口、数据库名称、用户名和密码寻常在composer安装的时候曾经设置好,但是你仍能在app/config/parameters.yml中编辑。

在那一个章节中,大家将写一些简短的数据库管理脚本。在此从前让我们来复习一下如何通过命令行方式举行Python脚本.

编写diff脚本

先是在档次创造diff文件,并给予执行权限。之后是基于地方的笔触来编排脚本,以下是完整代码示例:

#!/usr/bin/env php
<?php
require_once 'vendor/autoload.php';

use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Migrations\Provider\SchemaDiffProvider;
use Doctrine\DBAL\Schema\MySqlSchemaManager;
use Doctrine\DBAL\Schema\Schema;

// 读取数据库配置信息
$db_config = include 'config/db.php';
$db_params = [
    'driver' => 'pdo_mysql',
    'host' => $db_config['host'],
    'port' => $db_config['port'],
    'dbname' => $db_config['dbname'],
    'user' => $db_config['user'],
    'password' => $db_config['password'],
];
try {
    $connection = DriverManager::getConnection($db_params);
} catch (DBALException $e) {
    echo $e->getMessage() . PHP_EOL;
    exit;
}

// 获取数据库表结构
$schema_manager = new MySqlSchemaManager($connection);
$sdp = new SchemaDiffProvider($schema_manager, $schema_manager->getDatabasePlatform());
$from_schema = $sdp->createFromSchema();

// 获取写在脚本里面的表结构
$to_schema = new Schema();
$schema_class_list = glob(__DIR__ . '/db/tables/*.php');
foreach ($schema_class_list as $file) {
    require_once $file;
    $class = '\\db\\tables\\' . basename($file, '.php');
    if (class_exists($class)) {
        $cls = new $class;
        if (method_exists($cls, 'up')) {
            $cls->up($to_schema);
        }
    }
}

// 进行对比,输出结果
$diff = $sdp->getSqlDiffToMigrate($from_schema, $to_schema);
if ($diff) {
    foreach ($diff as $sql) {
        echo $sql . ';' . PHP_EOL;
    }
}

创建实体类

每一个实体(数据表)应代表为一个类,并且文件放置在AppBundle/Entity目录下:

// src/AppBundle/Entity/User.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;

class User
{
    private $id;
    private $name;
    private $email;
    private $password;
    private $createdAt;
} 

以此类表示了用户数据表,它兼具id,name,email,password和created_at字段。为了给Doctrine提供每一个字段的品种和涉嫌,大家还要写一些诠释:

 * @ORM\Entity
 * @ORM\Table(name="user")
 */
class User
{
   /**
    * @ORM\Id
    * @ORM\Column(type="integer")
    * @ORM\GeneratedValue(strategy="AUTO")
    */
    private $id;

   /**
    * @var string
    */
    private $name;

   /**
    * @var string
    */    
    private $email;

   /**
    * @var string
    */
    private $password;

    /**
     * @ORM\Column(type="datetime")
     */
     private $createdAt;

    /**
     * @ORM\ManyToOne(targetEntity="Group", inversedBy="users")
     * @ORM\JoinColumn(name="group_id", referencedColumnName="id")
     */
    private $group;

} 

表名的笺注是可选的,假如您省略了,Doctrine会按照类的名称去自动生成一个相应的表名。在上头的代码中,只展现了部分字段的性质。

今昔让大家来创立一个表用来叙述用户组,每一个用户只可以在里边一个用户组中:

// src/AppBundle/Entity/Group.php
/**
 * @ORM\Entity
 * @ORM\Table(name="group")
 */
class Group
{
   /**
    * @ORM\Id
    * @ORM\Column(type="integer")
    * @ORM\GeneratedValue(strategy="AUTO")
    */
    private $id;

   /**
    * @var string
    */
    private $name;

   /**
    * @ORM\Column(nullable=true) 
    * @ORM\Column(type="text")
    */    
    private $description;

   /**
    * @ORM\OneToMany(targetEntity="User", mappedBy="group")
    */
    private $users;

    public function __construct()
    {
        $this->users = new ArrayCollection();
    }

}

请留心,表关系一致被写在了诠释当中。OneToMany是一个关系的名目,targetEntity是一个实体类,JoinColumn定义了外键。同时,在OneToMany的关系中,大家须求在构造方法中扬言一个变量ArrayCollection。

Python的Flask框架与数据库连接的科目,Symfony框架中的Doctrine。类中的变量被定义为了个人变量,为了获取到那些私家变量,大家须求创制一个装置变量和得到变量的法子。你可以手动创制那么些方法,然而在您的系列目录中利用上边的指令可以轻松的落到实处:

php app/console doctrine:generate:entities AppBundle/Entity/User

在实践了上边的一声令下之后,User类会变成上边的指南:

/**
 * @ORM\Entity
 * @ORM\Table(name="user")
 */
class User
{
   /**
    * @ORM\Id
    * @ORM\Column(type="integer")
    * @ORM\GeneratedValue(strategy="AUTO")
    */
    private $id;

   /**
    * @var string
    */
    private $name;

   /**
    * @var string
    */    
    private $email;

   /**
    * @var string
    */
    private $password;

    /**
     * @ORM\Column(type="datetime")
     */
     private $createdAt;

    /**
     * @ORM\ManyToOne(targetEntity="Group", inversedBy="users")
     * @ORM\JoinColumn(name="group_id", referencedColumnName="id")
     */
    private $group;

    /**
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param mixed $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * @return mixed
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param mixed $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * @return mixed
     */
    public function getEmail()
    {
        return $this->email;
    }

    /**
     * @param mixed $email
     */
    public function setEmail($email)
    {
        $this->email = $email;
    }

    /**
     * @return mixed
     */
    public function getPassword()
    {
        return $this->password;
    }

    /**
     * @param mixed $password
     */
    public function setPassword($password)
    {
        $this->password = $password;
    }

    /**
     * @return mixed
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * @param mixed $createdAt
     */
    public function setCreatedAt($createdAt)
    {
        $this->createdAt = $createdAt;
    }

}

一经Linux 或者OS X的操作系统,须要有执行脚本的权限。例如:

diff方式的迁移使用

然后,所有的数目表都须要在根目录下db/tables目录里面建立相应的表结构脚本(任意文件名本),下边,大家以test_user表举例:

创立db/tables/testUser.php文件,编写代码:

<?php
namespace db\tables;

use Doctrine\DBAL\Schema\Schema;

class testUser
{
    public function up(Schema $schema): void
    {
        $table = $schema->createTable('test_user');
        $table->addColumn('id', 'integer')->setUnsigned(true)->setAutoincrement(true);
        $table->addColumn('name', 'string')->setLength(20)->setComment('用户名');
        $table->addColumn('age', 'integer')->setUnsigned(true)->setDefault(0)->setComment('年龄');
        $table->addColumn('sex', 'string')->setLength(2)->setDefault('')->setComment('性别');
        $table->addColumn('is_del', 'boolean')->setDefault(false)->setComment('是否删除');
        $table->setPrimaryKey(['id'])->addIndex(['is_del']);
    }
}

接下来在根目录执行./diff一声令下,就会晤到输出的sql音讯。

制造和立异数据库形式

在Doctrine中,在早就有了一个实体咧的根底上执行上面的通令可以随便的创办一个数据库情势:

php app/console doctrine:schema:update --force

地方的命令不仅可以成立数据库方式,同时在您的支出进度中还会更新数据库形式。在数据库中施行SQL查询的时候,不引进使用数据库形式,推荐在生产条件中革新。

chmod a+x script.py

添加黑名单过滤

到这一步diff格局的动迁已经能正常使用了,不过大家发现,即使是在已有的序列中途加入迁移成效时,使用diff命令会把已经存在的表删除掉,其余,也有时候会有其他表不须要管住的,大家就需求过滤掉那几个表。现在我们来添加黑名单效能。

在进行对照此前,参加以下代码:

// 过滤黑名单
$black_list = ['migration_versions', 'test1', 'test2', 'test3'];
foreach ($black_list as $black_table) {
    $from_schema->hasTable($black_table) && $from_schema->dropTable($black_table);
    $to_schema->hasTable($black_table) && $to_schema->dropTable($black_table);
}

再履行diff命令时,就会过滤掉$black_list变量数组里面的表,当然那些黑名单变量完全可以用别样安顿文件来顶替,可以自由情势的自定义。

数据库查询

到这一步,咱们已经创办了一个实体类,定义了它的表关系同时创建了数据库形式。现在大家将要学习如何在数据库中创立、查询、更新和删除数据。

$group = new Group();
$group->setName('Administrator');
$group->setDescription('Users with highest privileges in the system'); 

$em = $this->getDoctrine()->getManager();

// Tells Doctrine you want to save the group (no queries yet)
$em->persist($group);

// This line actually executes the SQL query
$em->flush();

在刚刚创制的用户组表中询问id:

$group->getId();

从数据库中查询数据:

$group = $this->getDoctrine()
        ->getRepository('AppBundle:Group)
        ->find($groupId); 

创新数据:

// Fetch the group
$em = $this->getDoctrine()->getManager();
$group = $em->getRepository('AppBundle:Group)->find($groupId);

// If the group does not exist, throw an exception
if (!$group) {
   throw $this->createNotFoundException(
      'Group not found'
   );
}

// Update data
$group>setDescription('New group description.');
$em->flush();

从数据库中剔除数据:

// Fetch group
$em = $this->getDoctrine()->getManager();
$group = $em->getRepository('AppBundle:Group)->find($groupId);

// Remove group
$em->remove($group);
$em->flush();

该脚本有个针对使用解释器的命令行。再脚本赋予执行权限后就可以通过命令行执行,如同这么:
like this:

本子增强

最好再对diff脚本进一步的增高,让它可以直接实施sql。

修改最终的对照代码为以下内容:

// 进行对比,输出结果
$diff = $sdp->getSqlDiffToMigrate($from_schema, $to_schema);
if (empty($diff)) {
    echo 'No need to update the schema.' . PHP_EOL;
} elseif ($diff) {
    $statement = '';
    foreach ($diff as $sql) {
        $statement .= $sql;
        echo $sql . ';' . PHP_EOL;
    }
    echo 'Do you want to execute these SQLs? (Y/n)';
    $flag = trim(fgets(STDIN));
    if ($flag === 'Y') {
        $connection->beginTransaction();
        try {
            $connection->executeUpdate($statement);
            $connection->commit();
        } catch (\Exception $e) {
            try {
                $connection->rollBack();
            } catch (ConnectionException $e) {
                echo $e->getMessage();
                exit;
            }
            echo $e->getMessage() . PHP_EOL;
            exit;
        }
        echo 'SQL executed successfully' . PHP_EOL;
    }
}

现在,执行diff命令时就会唤醒是还是不是须求实施sql(默认不履行)。

./script.py <arguments>

结语

后天,diff形式的数目迁移就曾经比较完美的并轨与品种中了,然而diff格局也有缺点,就是不可以对数据开展管理,比如偶尔菜单或者或者权力就须要多少也能一起。所以三种方式要依照自己的门类情况去选取。

此种类的有着代码都可以在小说最后的代码库链接中找到相应的代码,并且每一回commit对应每篇文章,方便读者对应小说和代码。

现行此连串就曾经终结,希望以此体系的稿子能对你使用数据迁移组件有所扶助,感谢您的翻阅,也期望提出您宝贵的见地。

在自我的代码库可以查阅这篇文章的详尽代码,欢迎star。

可是,在Windows系统上这么做是不行的,你不能够不提供Python解释器作为必选参数,如:

复制代码 代码如下:

flask/Scripts/python script.py <arguments>

为了幸免Python解释器路径输入出错,你可以将你的文件夹microoblog/flask/Scripts添加到系统路径,确保能健康呈现Python解释器。

从明日起初,在Linux/OS
X上的说话简洁。要是你使用Windows系统请记得转换语句。 
 
在Flask使用数据库

俺们将应用Flask-SQLAlchemy的扩大来管理数据库。由SQLAlchemy项目提供的,已打包了关乎对象映射(ORM)的一个插件。

ORMs允许数据库程序用对象的方法替代表和SQL语句。面向对象的操作被ORM转化为数据库命令。那样就象征,不用sql语句,让Flask-SQLAlchemy为咱们进行sql语句。
 
迁移

大部数据库教程都覆盖了成立和行使一个数据库的方法,不过尚未丰富解决当应用程序增加时数据库更新的难题。寻常,你会去除旧的数据库,然后再创造一个新的数据库来达到更新的功用,这样就不见了颇具的多少。假若这么些数量创建起来很忙碌,那么我们只可以写导入导出的脚本了。

有幸的是,大家有了更好的方案.

咱俩后天得以运用SQLAlchemy-migrate做数据库迁移的换代了,就算它伸张了数据库启动时的担当,但这一点小小的代价依然值得的,毕竟大家毫不顾虑手动迁移数据库的题材了。

答辩学习完结,大家起先吧!

配置

我们的小程序选拔sqlite数据库。sqlite是小程序数据库的最佳选取,一个足以以单文件存储的数据库。

在大家的布署文件中添加新的布署项 (fileconfig.py):
 

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

SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'app.db')
SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository')

SQLALCHEMY_DATABASE_URI是the
Flask-SQLAlchemy必需的恢宏。那是我们的数据库文件的门径。

SQLALCHEMY_MIGRATE_REPO
是用来存储SQLAlchemy-migrate数据库文件的文书夹。

说到底,开头化应用的时候也必要伊始化数据库。那里是擢升后的init文件(fileapp/__init):
 

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy

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

from app import views, models

小心生成的脚本已改变2个地点。大家后天开头创立数据库的adb对象,引用新的模块。立时来写那么些模块。

数据库模型

咱俩在数据库存储的多少通过数据库model层被映射为局地类里面的目的,ORM层将依照类对象映射到数据库对应的字段.

让我们来创制个映射到users的model。使用WWW SQL
Designer工具,大家创造了象征users表的一个图标: 

澳门葡京备用网址 1

 id字段常常作为主键的花样用在有着的models里面,每个在数据库中的user都有一个指定的唯一id值。幸运的是,这一个都是电动的,大家只必要提供一个id字段。

nickname和email字段被定义为string类型,他们的尺寸也已经被指定,这样可以节省数据库存储空间。

role字段被定义为integer类型,咱们用来标识users是admins如故其余连串。

近期大家已经鲜明了users表的构造,接下去转换为编码的工作将相当简单了(fileapp/models.py):
 

from app import db

ROLE_USER = 0
ROLE_ADMIN = 1

class User(db.Model):
  id = db.Column(db.Integer, primary_key = True)
  nickname = db.Column(db.String(64), index = True, unique = True)
  email = db.Column(db.String(120), index = True, unique = True)
  role = db.Column(db.SmallInteger, default = ROLE_USER)

  def __repr__(self):
    return '<User %r>' % (self.nickname)

User类把大家刚刚创造的多少个字段定义为类变量。字段使用db.Column类创立实例,字段的门类作为参数,其余还提供部分别样可选参数。例如,标识字段唯一性和目录的参数.

__repr__方式告诉Python怎样打印class对象,方便大家调试使用。

始建数据库

把布署和model放到正确的目录地点,现在我们制造数据库文件。SQLAlchemy-migrate包自带命令行工具和APIs来创立数据库,那样的章程得以方便将来更新。不过本人认为使用那几个命令行工具有些别扭,所以自己要好写了个python脚本来调用迁移的APIs.

此地有个创设数据库的脚本 (filedb_create.py):
 

#!flask/bin/python
from migrate.versioning import api
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
from app import db
import os.path
db.create_all()
if not os.path.exists(SQLALCHEMY_MIGRATE_REPO):
  api.create(SQLALCHEMY_MIGRATE_REPO, 'database repository')
  api.version_control(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
else:
  api.version_control(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, api.version(SQLALCHEMY_MIGRATE_REPO))

留意那些脚本是截然通用的,所有的利用路径名都是从配置文件读取的。当你用在投机的门类时,你可以把脚本拷贝到你app`s目录下就能正常使用了。

成立数据库你只须求周转上边的一条命令(注意windows下有些有点不一致):

./db_create.py

运行那条命令之后,你就创立了一个新的app.db文件。那是个匡助迁移的空sqlite数据库,同时也会变动一个含有多少个公文的db_repository目录,那是SQLAlchemy-migrate存储数据库文件的地点,注意如若数据库已存在它就不会再重新生成了。那将救助大家在丢失了现有的数据库后,再一次自动创立出来。.

首先次迁移

既然大家已经定义好了model,也把它和数据库做了关系,接下去大家来第一尝试下做一个改成使用数据库结构的三回迁移,那将帮扶大家从一个空的数据库变成一个足以存储users音讯的数据库。

做一个搬迁我利用另一个Python小助手脚本 (filedb_migrate.py):
 

#!flask/bin/python
import imp
from migrate.versioning import api
from app import db
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
migration = SQLALCHEMY_MIGRATE_REPO + '/versions/%03d_migration.py' % (api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO) + 1)
tmp_module = imp.new_module('old_model')
old_model = api.create_model(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
exec old_model in tmp_module.__dict__
script = api.make_update_script_for_model(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, tmp_module.meta, db.metadata)
open(migration, "wt").write(script)
a = api.upgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
print 'New migration saved as ' + migration
print 'Current database version: ' + str(api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO))

本条剧本看起来很复杂,其实做的东西真不多。SQLAlchemy-migrate通过对照数据库的协会(从app.db文件读取)和models结构(从app/models.py文件读取)的法门来创设迁移职分,两者之间的差异将作为一个搬迁脚本记录在搬迁库中,迁移脚本知道哪些使用或者废除一遍迁移,所以它可以一本万利的提拔或者降级一个数据库的格式。

虽说自己使用方面的脚本自动生成迁移时没遇上什么样难题,但有时候确实很难控制数据库旧格式和新格式究竟有吗改变。为了让SQLAlchemy-migrate更易于确定数据库的更动,我从未给现有字段重命名,限制了丰裕删减models、字段,或者对现有字段的项目修改。我再而三检查下生成的搬迁脚本是还是不是科学。

并非多讲,在你打算迁移数据库前必须做好备份,以免出现难点。不要在生养用的数据库上运行第一遍选择的本子,先在付出用的数据库上运行下。

继承提升,记录下大家的迁移:

./db_migrate.py

剧本将打印出以下信息:

New migration saved as db_repository/versions/001_migration.py Current database version: 1

其一本子信息体现了迁移脚本的寄放地方,还有当前数据库的版本号。空数据库的版本号是0,当大家导入users音讯后版本号成为1.

数据库的擢升和回滚

现行你恐怕想驾驭怎么大家要做额外的工作来做数据库的迁徙记录。

试想一下,你有个应用在付出机器上,同时服务器上也有一个复制的利用正在运作。

比方说,在您产品的下个本子你的models层作了修改,比如伸张了一个新表。没有迁移文件的话,你须求同时解决在开发机和服务器上数据库格式修改的题材,那将是个很大的工作量。

若果你早就有了一个支撑迁移的数据库,那么当你向生产服务器公布新的运用版本时,你只须求记录下新的搬迁记录,把迁移脚本拷贝到你的生产服务器上,然后运行一个概括的使用改变脚本就行。数据库的升官可以利用上面的Python脚本(filedb_upgrade.py):
 

#!flask/bin/python
from migrate.versioning import api
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
api.upgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
print 'Current database version: ' + str(api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO))

当你运行方面的本申时,数据库将升任到最新版本,并通过脚本将转移音讯存储到数据库中。

把数据库回滚到旧的格式,那是不常见的一个方法,但避防万一,SQLAlchemy-migrate也很好的支撑(filedb_downgrade.py):
 

#!flask/bin/python
from migrate.versioning import api
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
api.downgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, v - 1)
print 'Current database version: ' + str(api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO))

其一本子将回滚数据库的一个版本,你可以因而运行往往的法门前进回滚三个版本。

数据库关联

关系型数据库最善于存储数据里面的关系。如若用户会写一篇和讯,用户的新闻被积存在users表中,今日头条存储在post表中。记录何人写的乐乎最有效的法门是起家两条数据里面的关联.

假定用户和新浪的关联表建立将来,大家有三种查询办法可以选拔。.最琐碎的一个就是当你见到一篇腾讯网,你想精晓是哪个用户写的。更复杂的一个是反向的查询,如果您明白一个用户,你想打听下她写的全部和讯。Flask-SQLAlchemy将给大家提供对两种办法查询的支援。

让大家对数码做一下伸张来囤积和讯音信,这样大家就能见到相应的涉及了。我们回来我们拔取的数据库设计工具来创制个posts表: 

澳门葡京备用网址 2

 posts表包括一个亟须的id,博客园的始末body,还有一个年华戳。没有怎么新东西,不过user_id字段值得解释下。

俺们想建立用户和她俩写的和讯之间的涉及,那种方式就是通过抬高一个暗含用户id的字段来标识哪个人写的博客园,那一个id叫做外键。我们的数据库设计工具也出示了外键作为一个外键和id字段指向表的总是。那种关涉叫做一对多关系,也就是一个用户可以写多篇小说。

 

让我们修改下models来响应那个变化 (app/models.py):
 

from app import db

ROLE_USER = 0
ROLE_ADMIN = 1

class User(db.Model):
  id = db.Column(db.Integer, primary_key = True)
  nickname = db.Column(db.String(64), unique = True)
  email = db.Column(db.String(120), unique = True)
  role = db.Column(db.SmallInteger, default = ROLE_USER)
  posts = db.relationship('Post', backref = 'author', lazy = 'dynamic')

  def __repr__(self):
    return '<User %r>' % (self.nickname)

class Post(db.Model):
  id = db.Column(db.Integer, primary_key = True)
  body = db.Column(db.String(140))
  timestamp = db.Column(db.DateTime)
  user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

  def __repr__(self):
    return '<Post %r>' % (self.body)

大家扩张了一个象征用户写的腾讯网的Post类,user_id字段在Post类中被开首化指定为一个外键,由此Flask-SQLAlchemy会知道那么些字段将会和用户做涉嫌。

专注大家还在User类中添加了一个新字段命名为posts,它被定义成一个db.relationship字段,这些字段并非是数据库中实际上存在的字段,所以它不在大家的数据库图表中。对于有些多的涉嫌db.relationship字段寻常只须求在一面定义。依照那几个关系我们可以收获到用户的和讯列表。db.relationship的第三个参数表示“many”一方的类名。backref参数定义了一个字段将”many”类的靶子指回到”one”对象,就大家而言,大家得以选择psot.author获取到User实例创设一个搜狐。如果领会不了不要顾虑,在篇章的前面我们将透过一个例子来诠释。

让大家用其余一个搬迁文件记录下这一次的转移。简单运行上边脚本:

./db_migrate.py

运行脚本后将获取如下输出:

New migration saved as db_repository/versions/002_migration.py Current database version: 2

大家没须要每一次都用一个单独的迁徙文件来记录数据库model层的小变化,一个搬迁文件一般只是记录一个发表版本的变更。接下来更要紧的业务是我们要求精晓下迁移系统的劳作规律。

采用实践

咱俩早就花了汪洋的时光在数据库定义上,不过大家如故没有看出她是什么样行事的,因为大家的应用程序里没有任何的数目相关的编码,接下去大家将在Python解释器里选择我们的崭新数据库吧。

持续前行,启动Python。 在 Linux 或者 OS X:

复制代码 代码如下:

flask/bin/python

Windows下:

复制代码 代码如下:

flask/Scripts/python

当您在Python命令行提示符中输入上面音讯:

>>> from app import db, models >>>

那样我们的数据库模块和models就被加载到了内存里.

让我们来创设个新用户:
 

>>> u = models.User(nickname='john', email='john@email.com', role=models.ROLE_USER)
>>> db.session.add(u)
>>> db.session.commit()
>>>

在同一个对话环境下转移数据库,很多次的修改可以积累到一个对话中最后经过调用一个db.session.commit()命令提交,提交同时也准保了原子性。如果在对话中冒出了错误,会调用db.session.rollback()把数据库回滚到会话从前的场所。倘诺调用的既不是提交也不是回滚,那么系统会默许回滚这么些会话。Sessions(会话)保障了数据库的多寡一致性。
 

让大家来丰裕别的一个用户:
 

>>> u = models.User(nickname='susan', email='susan@email.com', role=models.ROLE_USER)
>>> db.session.add(u)
>>> db.session.commit()
>>>

现今大家可以查询出用户新闻:
 

>>> users = models.User.query.all()
>>> print users
[<User u'john'>, <User u'susan'>]
>>> for u in users:
...   print u.id,u.nickname
...
1 john
2 susan
>>>

那边大家选择了query查询函数,在装有的model类中都可以选择这么些函数。注意id是怎么着自动生成的。

再有别的一种方法来查询,假使大家领略了用户的id,我们能够利用下边的主意查找用户音讯:
 

>>> u = models.User.query.get(1)
>>> print u
<User u'john'>
>>>

现在让大家添加一条新浪音讯:
 

>>> import datetime
>>> u = models.User.query.get(1)
>>> p = models.Post(body='my first post!', timestamp=datetime.datetime.utcnow(), author=u)
>>> db.session.add(p)
>>> db.session.commit()

其一地方我们把时光设置为UTC时区,所有的仓储在数据库里的时日将是UTC格式,用户可能在世界各州写博客园,由此大家须求选取统一的时光单位。在将来的课程中我们将学习怎么样在用户本地时区使用这一个日子。

您也许注意到大家从没在Post类中装置user_id字段,取而代之的是把用户对象存储到了author字段。auhtor字段是个经过Flask-SQLAlchemy添加的虚拟字段用来树立关联关系的,我们事先早已定义好了那几个名字,参照:model中的db.relationship中backref参数。通过那几个音信,ORM层就能知晓什么取到user_id。

要到位这几个会话,让我们来探望更多可做的数据库查询:
 

# get all posts from a user
>>> u = models.User.query.get(1)
>>> print u
<User u'john'>
>>> posts = u.posts.all()
>>> print posts
[<Post u'my first post!'>]

# obtain author of each post
>>> for p in posts:
...   print p.id,p.author.nickname,p.body
...
1 john my first post!

# a user that has no posts
>>> u = models.User.query.get(2)
>>> print u
<User u'susan'>
>>> print u.posts.all()
[]

# get all users in reverse alphabetical order
>>> print models.User.query.order_by('nickname desc').all()
[<User u'susan'>, <User u'john'>]
>>>

要打听越来越多的数据库查询选择,最好的不二法门就是去看
Flask-SQLAlchemy的文档。

在终止会话此前,大家把以前制造的测试用户和文章删除掉,就足以在接下去的章节,从一个根本的数据库开首:
 

>>> users = models.User.query.all()
>>> for u in users:
...   db.session.delete(u)
...
>>> posts = models.Post.query.all()
>>> for p in posts:
...   db.session.delete(p)
...
>>> db.session.commit()
>>>

结束语

这一长篇新手入门,大家询问到了数据库的基本操作,但大家还并未将数据库关联到程序中。在下一个章节中我们因而用户登录种类来磨炼所学的数据库操作。

在此同时,即使您还没初叶写程序,你要求下载当前文件
microblog-0.4.zip.只顾,zip文件中从不包罗数据库,可是已经有囤积脚本。用db_create.py创建一个新的数据库,用db_upgrade.py把您的数据库升级到新型版本。

您或许感兴趣的篇章:

  • Python的Flask框架中利用Flask-SQLAlchemy管理数据库的教程
  • 在Python程序和Flask框架中行使SQLAlchemy的科目
  • Python利用flask
    sqlalchemy已毕分页效果
  • Python的Flask框架中SQLAlchemy使用时的乱码难点化解
  • 在Python的Flask框架下使用sqlalchemy库的简易教程
  • Python的Flask框架中采纳Flask-Migrate扩充迁移数据库的学科
  • Python框架Flask的中坚数据库操作方法分析
  • Python使用Flask-SQLAlchemy连接数据库操作示例

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website