【Python百日进阶-Web开发-Peewee】Day289 - Peewee 的扩展(九)pwiz / 架构迁移(上)

文章目录

    • 13.15 pwiz,模型生成器
      • 13.15.1 命令行选项
    • 13.16 架构迁移 Schema Migrations
      • 13.16.1 示例用法
      • 13.16.2 支持的操作

13.15 pwiz,模型生成器

pwiz是 peewee 附带的一个小脚本,能够自省现有数据库并生成适合与底层数据交互的模型代码。如果您已经有一个数据库,pwiz 可以通过生成具有正确列关联和外键的骨架代码来给您一个很好的提升。

如果您使用 安装 peewee ,pwiz 将作为“脚本”安装,您可以运行:setup.py install

python -m pwiz -e postgresql -u postgres my_postgres_db

这会将一堆模型打印到标准输出。所以你可以这样做:

python -m pwiz -e postgresql my_postgres_db > mymodels.py
python # <-- fire up an interactive shell
>>> from mymodels import Blog, Entry, Tag, Whatever
>>> print([blog.name for blog in Blog.select()])

13.15.1 命令行选项

pwiz 接受以下命令行选项:

选项 意义 例子
-H 显示帮助
-e 数据库后端 -e mysql
-H 要连接的主机 -H 远程数据库服务器
-p 要连接的端口 -p 9001
-u 数据库用户 -u postgres
-P 数据库密码 -P(将提示输入密码)
-s 图式 -s 公开
-t 要生成的表 -t 推文,用户,关系
-v 为 VIEW 生成模型 (no argument)
-i 将信息元数据添加到生成的文件 (no argument)
-o 保留表列顺序 (no argument)
以下是engine( -e) 的有效参数:
  • sqlite
  • mysql
  • PostgreSQL

警告
如果访问数据库需要密码,系统将提示您使用安全提示输入密码。

密码将包含在输出中。具体来说,在文件的顶部,aDatabase将与任何必需的参数一起定义——包括密码。

奖品例子
自省各种数据库的示例:

# Introspect a Sqlite database.
python -m pwiz -e sqlite path/to/sqlite_database.db

# Introspect a MySQL database, logging in as root. You will be prompted
# for a password ("-P").
python -m pwiz -e mysql -u root -P mysql_db_name

# Introspect a Postgresql database on a remote server.
python -m pwiz -e postgres -u postgres -H 10.1.0.3 pg_db_name

完整示例:

$ sqlite3 example.db << EOM
CREATE TABLE "user" ("id" INTEGER NOT NULL PRIMARY KEY, "username" TEXT NOT NULL);
CREATE TABLE "tweet" (
    "id" INTEGER NOT NULL PRIMARY KEY,
    "content" TEXT NOT NULL,
    "timestamp" DATETIME NOT NULL,
    "user_id" INTEGER NOT NULL,
    FOREIGN KEY ("user_id") REFERENCES "user" ("id"));
CREATE UNIQUE INDEX "user_username" ON "user" ("username");
EOM

$ python -m pwiz -e sqlite example.db

产生以下输出:

from peewee import *

database = SqliteDatabase('example.db', **{})

class UnknownField(object):
    def __init__(self, *_, **__): pass

class BaseModel(Model):
    class Meta:
        database = database

class User(BaseModel):
    username = TextField(unique=True)

    class Meta:
        table_name = 'user'

class Tweet(BaseModel):
    content = TextField()
    timestamp = DateTimeField()
    user = ForeignKeyField(column_name='user_id', field='id', model=User)

    class Meta:
        table_name = 'tweet'

观察:

  • 外键Tweet.user_id被正确检测和映射。
  • User.username检测到 UNIQUE 约束。
  • 每个模型都显式声明其表名,即使在没有必要的情况下也是如此(因为 Peewee 会自动将类名转换为适当的表名)。
  • 的所有参数ForeignKeyField都是显式声明的,即使它们遵循 Peewee 默认使用的约定。

笔记
是一个占位符,在UnknownField您的架构包含 Peewee 不知道如何映射到字段类的列声明时使用。

13.16 架构迁移 Schema Migrations

Peewee 现在支持模式迁移,对 Postgresql、SQLite 和 MySQL 提供了经过充分测试的支持。与其他模式迁移工具不同,peewee 的迁移不处理内省和数据库“版本控制”。相反,peewee 提供了许多帮助函数来生成和运行模式更改语句。该引擎提供了有朝一日可以构建更复杂工具的基础。

迁移可以编写为简单的 python 脚本并从命令行执行。由于迁移仅取决于您的应用程序 Database对象,因此应该很容易管理更改模型定义并维护一组迁移脚本而无需引入依赖项。

13.16.1 示例用法

首先从migrate模块导入助手:

from playhouse.migrate import *

实例化一个migrator. 该类SchemaMigrator负责生成模式更改操作,然后可以由migrate()助手按顺序运行。

# Postgres example:
my_db = PostgresqlDatabase(...)
migrator = PostgresqlMigrator(my_db)

# SQLite example:
my_db = SqliteDatabase('my_database.db')
migrator = SqliteMigrator(my_db)

用于migrate()执行一项或多项操作:

title_field = CharField(default='')
status_field = IntegerField(null=True)

migrate(
    migrator.add_column('some_table', 'title', title_field),
    migrator.add_column('some_table', 'status', status_field),
    migrator.drop_column('some_table', 'old_column'),
)

警告
迁移不在事务内运行。如果您希望迁移在事务中运行,您需要将调用包装在上下文 atomic()管理器中,例如

with my_db.atomic():
    migrate(...)

13.16.2 支持的操作

向现有模型添加新字段:

# Create your field instances. For non-null fields you must specify a
# default value.
pubdate_field = DateTimeField(null=True)
comment_field = TextField(default='')

# Run the migration, specifying the database table, field name and field.
migrate(
    migrator.add_column('comment_tbl', 'pub_date', pubdate_field),
    migrator.add_column('comment_tbl', 'comment', comment_field),
)

重命名字段:

# Specify the table, original name of the column, and its new name.
migrate(
    migrator.rename_column('story', 'pub_date', 'publish_date'),
    migrator.rename_column('story', 'mod_date', 'modified_date'),
)

删除一个字段:

migrate(
    migrator.drop_column('story', 'some_old_field'),
)

使字段可空或不可空:

# Note that when making a field not null that field must not have any
# NULL values present.
migrate(
    # Make `pub_date` allow NULL values.
    migrator.drop_not_null('story', 'pub_date'),

    # Prevent `modified_date` from containing NULL values.
    migrator.add_not_null('story', 'modified_date'),
)

更改字段的数据类型:

# Change a VARCHAR(50) field to a TEXT field.
migrate(
    migrator.alter_column_type('person', 'email', TextField())
)

重命名表:

migrate(
    migrator.rename_table('story', 'stories_tbl'),
)

添加索引:

# Specify the table, column names, and whether the index should be
# UNIQUE or not.
migrate(
    # Create an index on the `pub_date` column.
    migrator.add_index('story', ('pub_date',), False),

    # Create a multi-column index on the `pub_date` and `status` fields.
    migrator.add_index('story', ('pub_date', 'status'), False),

    # Create a unique index on the category and title fields.
    migrator.add_index('story', ('category_id', 'title'), True),
)

删除索引:

# Specify the index name.
migrate(migrator.drop_index('story', 'story_pub_date_status'))

添加或删除表约束:

# Add a CHECK() constraint to enforce the price cannot be negative.
migrate(migrator.add_constraint(
    'products',
    'price_check',
    Check('price >= 0')))

# Remove the price check constraint.
migrate(migrator.drop_constraint('products', 'price_check'))

# Add a UNIQUE constraint on the first and last names.
migrate(migrator.add_unique('person', 'first_name', 'last_name'))

笔记
Postgres 用户在使用非标准模式时可能需要设置搜索路径。这可以按如下方式完成:

new_field = TextField(default='', null=False)
migrator = PostgresqlMigrator(db)
migrate(migrator.set_search_path('my_schema_name'),
        migrator.add_column('table', 'field_name', new_field))

你可能感兴趣的:(数据库,python,dash,前端)