美文网首页我爱编程
PyMySQL 和 SQLAlchemy使用

PyMySQL 和 SQLAlchemy使用

作者: 子非初心 | 来源:发表于2018-05-21 18:40 被阅读448次

    MySQL 命令大全

    DDL(数据定义语句)

    CREATE TABLE/DATABASE

    ALTER TABLE/DATABASE

    DROP TABLE/DATABASE

    DML(数据管理语句)

    INSERT => 新增

    DELETE => 删除

    UPDATE => 更新

    SELECT => 查询

    创建数据库

    —创建并使用数据库

    CREATE DATABASE mydatabase; 创建数据库

    USE mydatabase; 使用数据库

    —查看已有的数据库

    SHOW DATABASES;

    建表

    建表语句

    <pre class="md-fences md-end-block" lang="sql" contenteditable="false" cid="n554" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">CREATE TABLE students(
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(200) NOT NULL
    );</pre>

    常见类型

    int,char,varchar,datetime

    例子:

    <pre class="md-fences md-end-block" lang="sql" contenteditable="false" cid="n580" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">-- 新建数据库
    CREATE DATABASE school;

    -- 使用数据库
    USE school;

    -- id : 学生的ID
    -- name: 学生名称
    -- nickname: 学生的昵称
    -- sex: 性别
    -- in_time: 入学的时间
    CREATE TABLE students(
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(20) NOT NULL,
    nickname VARCHAR(20) NULL,
    sex CHAR(1) NULL,
    in_time DATETIME(20) NULL,
    PRIMARY KEY (id)
    ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;

    -- 插入数据
    INSERT INTO students(1,'张三','san',now());

    -- 删除表
    DROP TABLE IF EXISTS students;

    -- 查询
    SELECT * FROM students;

    -- 查询语句
    SELECT
    select_expr, ...
    FROM table_references -- table_references 表来源
    [WHERE where_definition] -- where_definition 条件
    [GROUP BY {col_name | expr | position}]
    [HAVING where_definition]
    [ORDER BY {col_name | expr | position}
    [ASC | DESC],...]
    [LIMIT {[offset,] row_count}] -- LIMIT限制查询条数 offset(偏移量,从哪开始), row_count(查询的条数)

    -- 条件查询
    SELECT * FROM student WHERE sex='男';
    SELECT id,name,nickname FROM student WHERE sex='男' ORDER BY id DESC;

    -- 修改(更新)
    UPDATE table_references
    SET col_name1=expr1[, col_name2=expr2 ...]
    [WHERE where_definition]

    -- 更新操作
    UPDATE student SET sex = '女' WHERE sex = '男';
    UPDATE student SET sex = '女' WHERE id > 5;

    -- 其他操作
    CREATE INDEX -- 新建索引
    ALTER TABLE -- 修改表
    DROP -- 删除数据库、表、索引、视图等</pre>

    <figure class="md-table-fig" contenteditable="false" cid="n307" mdtype="table" style="box-sizing: border-box; margin: -8px 0px 0px -8px; overflow-x: auto; max-width: calc(100% + 16px); padding: 8px;">

    命令 说明
    net start mysql 启动数据库
    net stop mysql 关闭数据库
    mysql -u root -p 根据用户名密码,登录数据库
    mysql -u root 如果数据库没有密码则使用
    show databases; 查看在当前服务器中有多少个数据库
    drop database databaseName; 删除某个数据库
    commit; 提交
    CREATE DATABASE db_name DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 创建数据库
    ALTER DATABASE db_name DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 更改数据库的字符编码
    use databaseName; 选择使用某个数据库
    show tables; 查看数据库中有多少的表
    drop table tableName; 删除表
    describe tableName; 显示表结构
    SET PASSWORD FOR 'root'``@``'localhost' = ``PASSWORD``(``'newpass'``); 方法1: 用SET PASSWORD命令
    方法2:用mysqladmin

    </figure>

    方法1: 用SET PASSWORD命令

    MySQL -u root

    mysql> ``SET PASSWORD FOR 'root'``@``'localhost' = ``PASSWORD``(``'newpass'``);

    方法2:用mysqladmin

    mysqladmin -u root ``password "newpass"

    如果root已经设置过密码,采用如下方法

    mysqladmin -u root ``password oldpass ``"newpass"

    方法3: 用UPDATE直接编辑user表

    mysql -u root

    mysql> use mysql;

    mysql> ``UPDATE user SET Password = ``PASSWORD``(``'newpass'``) ``WHERE user = ``'root'``;

    mysql> FLUSH ``PRIVILEGES``;

    在丢失root密码的时候,可以这样

    mysqld_safe ``--skip-grant-tables&

    mysql -u root mysql

    mysql> ``UPDATE user SET password``=``PASSWORD``(``"new password"``) ``WHERE user``=``'root'``;

    mysql> FLUSH ``PRIVILEGES``;

    快捷命令说明:

    ​ command + w 关闭标签command + 数字 command + 左右方向键 切换标签command + enter 切换全屏command + f 查找command + d 垂直分屏command + shift + d 水平分屏command + option + 方向键 command + [ 或 command + ] 切换屏幕command + ; 查看历史命令command + shift + h 查看剪贴板历史ctrl + u 清除当前行ctrl + l 清屏ctrl + a 到行首ctrl + e 到行尾ctrl + f/b 前进后退ctrl + p 上一条命令ctrl + r 搜索命令历史

    新闻表设计

    字段说明

    <pre class="md-fences md-end-block" lang="sql" contenteditable="false" cid="n599" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">-- ID: 新闻的唯一标识
    -- title: 新闻的标题
    -- content: 新闻的内容
    -- create_time: 新闻添加的时间
    -- types: 新闻的类型
    -- image: 新的缩略图
    -- author: 作者
    -- view_count: 浏览量
    -- is_valid: 删除标记
    CREATE TABLE news(
    id INT NOT NULL AUTO_INCREMENT,
    title VARCHAR(200) NOT NULL,
    content VARCHAR(2000) NOT NULL,
    types VARCHAR(10) NOT NULL,
    image VARCHAR(300) NULL,
    author VARCHAR(20) NULL,
    view_count INT DEFAULT 0,
    create_time DATETIME NULL,
    is_valid SMALLINT DEFAULT 1,
    PRIMARY KEY (id)
    ) DEFAULT CHARSET = 'UTF8'

    -- 任务
    -- 1、创建一个数据库,然后设计一个新闻表(数据类型要使用合理)
    -- 2、使用SQL语句向数据表写入十五条不同的数据
    -- 3、使用SQL语句查询类别为"百家"的新闻数据
    -- 4、使用SQL语句删除一条新闻数据
    -- 5、使用SQL语句查询所有的新闻,以添加时间的倒序进行排列
    -- 6、使用SQL语句查询第二页(每一页5条数据)</pre>

    Flask-SQLAlchemy使用

    Queck-Start快速上手

    <pre class="md-fences md-end-block" lang="python" contenteditable="false" cid="n625" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">"""

    """
    from flask import Flask
    from flask-sqlachemy improt SQLAlchemy

    app = Flask(name)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'

    class User(db.Model)
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nuallable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

    def repr(self):
    return '<User %r>' % self.username</pre>

    为了创建初始数据库,只需db从交互式Python shell 导入对象并运行该SQLAlchemy.create_all()方法来创建表和数据库:

    <pre class="md-fences md-end-block" lang="shell" contenteditable="false" cid="n644" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">>>> from yourapplication import db

    db.create_all()</pre>

    接着,需要给你的数据库添加一些数据,例如新增两个用户:

    <pre class="md-fences md-end-block" lang="shell" contenteditable="false" cid="n655" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">>>> from yourapplication import User

    admin = User(username='admin', email='admin@example.com')
    guest = User(username='guest', email='guest@example.com')</pre>

    但是它们还没有真正地写入到数据库中,因此让我们来确保它们已经写入到数据库中:

    <pre class="md-fences md-end-block" lang="" contenteditable="false" cid="n668" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">>>> db.session.add(admin)

    db.session.add(guest)
    db.session.commit()</pre>

    访问数据库中的数据很简单:

    <pre class="md-fences md-end-block" lang="" contenteditable="false" cid="n679" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">>>> User.query.all()
    [<User u'admin'>, <User u'guest'>]

    User.query.filter_by(username='admin').first()
    <User u'admin'></pre>

    最简单的关系型数据库

    SQLAlchemy 连接到关系型数据库,关系型数据最擅长的东西就是关系。因此,我们将创建一个使用两张相互关联的表的应用作为例子:

    <pre class="md-fences md-end-block" lang="python" contenteditable="false" cid="n721" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">from datetime import datetime


    class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(80))
    body = db.Column(db.Text)
    pub_date = db.Column(db.DateTime)

    category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
    category = db.relationship('Category',
    backref=db.backref('posts', lazy='dynamic'))

    def init(self, title, body, category, pub_date=None):
    self.title = title
    self.body = body
    if pub_date is None:
    pub_date = datetime.utcnow()
    self.pub_date = pub_date
    self.category = category

    def repr(self):
    return '<Post %r>' % self.title


    class Category(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))

    def init(self, name):
    self.name = name

    def repr(self):
    return '<Category %r>' % self.name</pre>

    首先让我们创建一些对象:

    <pre class="md-fences md-end-block" lang="" contenteditable="false" cid="n739" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">>>> py = Category('Python')

    p = Post('Hello Python!', 'Python is pretty cool', py)
    db.session.add(py)
    db.session.add(p)</pre>

    现在因为我们在 backref 中声明了 posts 作为动态关系,查询显示为:

    <pre class="md-fences md-end-block" lang="" contenteditable="false" cid="n757" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">>>> py.posts
    <sqlalchemy.orm.dynamic.AppenderBaseQuery object at 0x1027d37d0></pre>

    它的行为像一个普通的查询对象,因此我们可以查询与我们测试的 “Python” 分类相关的所有文章(posts):

    <pre class="md-fences md-end-block" lang="" contenteditable="false" cid="n775" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">>>> py.posts.all()
    [<Post 'Hello Python!'>]</pre>

    启蒙之路

    您仅需要知道与普通的 SQLAlchemy 不同之处:

    1. SQLAlchemy允许您访问下面的东西:

    2. Model 声明基类行为类似一个常规的 Python 类,不过有个 query 属性,可以用来查询模型 (ModelBaseQuery)

    3. 您必须提交会话,但是没有必要在每个请求后删除它(session),Flask-SQLAlchemy 会帮您完成删除操作。

    配置

    下面是 Flask-SQLAlchemy 中存在的配置值。Flask-SQLAlchemy 从您的 Flask 主配置中加载这些值。 注意其中的一些在引擎创建后不能修改,所以确保尽早配置且不在运行时修改它们。

    配置键

    Flask-SQLAlchemy 扩展能够识别的配置键的清单:

    <figure class="md-table-fig" contenteditable="false" cid="n953" mdtype="table" style="box-sizing: border-box; margin: -8px 0px 0px -8px; overflow-x: auto; max-width: calc(100% + 16px); padding: 8px;">

    SQLALCHEMY_DATABASE_URI 用于连接数据的数据库。例如:sqlite:////tmp/test.db``mysql://username:password@server/db
    SQLALCHEMY_BINDS 一个映射绑定 (bind) 键到 SQLAlchemy 连接 URIs 的字典。 更多的信息请参阅 绑定多个数据库
    SQLALCHEMY_ECHO 如果设置成 True,SQLAlchemy 将会记录所有 发到标准输出(stderr)的语句,这对调试很有帮助。
    SQLALCHEMY_RECORD_QUERIES 可以用于显式地禁用或者启用查询记录。查询记录 在调试或者测试模式下自动启用。更多信息请参阅get_debug_queries()
    SQLALCHEMY_NATIVE_UNICODE 可以用于显式地禁用支持原生的 unicode。这是 某些数据库适配器必须的(像在 Ubuntu 某些版本上的 PostgreSQL),当使用不合适的指定无编码的数据库 默认值时。
    SQLALCHEMY_POOL_SIZE 数据库连接池的大小。默认是数据库引擎的默认值 (通常是 5)。
    SQLALCHEMY_POOL_TIMEOUT 指定数据库连接池的超时时间。默认是 10。
    SQLALCHEMY_POOL_RECYCLE 自动回收连接的秒数。这对 MySQL 是必须的,默认 情况下 MySQL 会自动移除闲置 8 小时或者以上的连接。 需要注意地是如果使用 MySQL 的话, Flask-SQLAlchemy 会自动地设置这个值为 2 小时。
    SQLALCHEMY_MAX_OVERFLOW 控制在连接池达到最大值后可以创建的连接数。当这些额外的 连接回收到连接池后将会被断开和抛弃。
    SQLALCHEMY_TRACK_MODIFICATIONS 如果设置成 True (默认情况),Flask-SQLAlchemy 将会追踪对象的修改并且发送信号。这需要额外的内存, 如果不必要的可以禁用它。

    </figure>

    连接 URI 格式

    完整连接 URI 格式列表请跳转到 SQLAlchemy 下面的文档(支持的数据库)。这里展示了一些常见的连接字符串。

    SQLAlchemy 把一个引擎的源表示为一个连同设定引擎选项的可选字符串参数的 URI。URI 的形式是:

    <pre class="md-fences md-end-block" lang="" contenteditable="false" cid="n1003" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">dialect+driver://username:password@host:port/database</pre>

    该字符串中的许多部分是可选的。如果没有指定驱动器,会选择默认的(确保在这种情况下 包含 + )。

    Postgres:

    <pre class="md-fences md-end-block" lang="" contenteditable="false" cid="n1008" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">postgresql://scott:tiger@localhost/mydatabase</pre>

    MySQL:

    <pre class="md-fences md-end-block" lang="" contenteditable="false" cid="n1011" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">mysql://scott:tiger@localhost/mydatabase</pre>

    Oracle:

    <pre class="md-fences md-end-block" lang="" contenteditable="false" cid="n1014" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">oracle://scott:tiger@127.0.0.1:1521/sidname</pre>

    SQLite (注意开头的四个斜线):

    <pre class="md-fences md-end-block" lang="" contenteditable="false" cid="n1017" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">sqlite:////absolute/path/to/foo.db</pre>

    声明模型

    通常下,Flask-SQLAlchemy 的行为就像一个来自 declarative 扩展配置正确的 declarative 基类。因此,我们强烈建议您阅读 SQLAlchemy 文档以获取一个全面的参考。尽管如此,我们这里还是给出了最常用的示例。

    需要牢记的事情:

    • 您的所有模型的基类叫做 db.Model。它存储在您必须创建的 SQLAlchemy 实例上。 细节请参阅 快速入门

    • 有一些部分在 SQLAlchemy 上是必选的,但是在 Flask-SQLAlchemy 上是可选的。 比如表名是自动地为您设置好的,除非您想要覆盖它。它是从转成小写的类名派生出来的,即 “CamelCase” 转换为 “camel_case”。

    简单示例

    一个非常简单的例子:

    <pre class="md-fences md-end-block" lang="" contenteditable="false" cid="n1037" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)

    def init(self, username, email):
    self.username = username
    self.email = email

    def repr(self):
    return '<User %r>' % self.username</pre>

    Column 来定义一列。列名就是您赋值给那个变量的名称。如果您想要在表中使用不同的名称,您可以提供一个想要的列名的字符串作为可选第一个参数。主键用 primary_key=True 标记。可以把多个键标记为主键,此时它们作为复合主键。

    列的类型是 Column 的第一个参数。您可以直接提供它们或进一步规定(比如提供一个长度)。下面的类型是最常用的:

    <figure class="md-table-fig" contenteditable="false" cid="n1042" mdtype="table" style="box-sizing: border-box; margin: -8px 0px 0px -8px; overflow-x: auto; max-width: calc(100% + 16px); padding: 8px;">

    Integer 一个整数
    String (size) 有长度限制的字符串
    Text 一些较长的 unicode 文本
    DateTime 表示为 Python datetime 对象的 时间和日期
    Float 存储浮点值
    Boolean 存储布尔值
    PickleType 存储为一个持久化的 Python 对象
    LargeBinary 存储一个任意大的二进制数据

    </figure>

    一对多(one-to-many)关系

    最为常见的关系就是一对多的关系。因为关系在它们建立之前就已经声明,您可以使用 字符串来指代还没有创建的类(例如如果 Person 定义了一个到 Article 的关系,而 Article在文件的后面才会声明)。

    关系使用 relationship() 函数表示。然而外键必须用类 sqlalchemy.schema.ForeignKey 来单独声明:

    <pre class="md-fences md-end-block" lang="" contenteditable="false" cid="n1072" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    addresses = db.relationship('Address', backref='person',
    lazy='dynamic')

    class Address(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(50))
    person_id = db.Column(db.Integer, db.ForeignKey('person.id'))</pre>

    db.relationship() 做了什么?这个函数返回一个可以做许多事情的新属性。在本案例中,我们让它指向 Address 类并加载多个地址。它如何知道会返回不止一个地址?因为 SQLALchemy 从您的声明中猜测了一个有用的默认值。 如果您想要一对一关系,您可以把 uselist=False 传给 relationship()

    那么 backref 和 lazy 意味着什么了?backref 是一个在 Address 类上声明新属性的简单方法。您也可以使用 my_address.person 来获取使用该地址(address)的人(person)。lazy 决定了 SQLAlchemy 什么时候从数据库中加载数据:

    • 'select' (默认值) 就是说 SQLAlchemy 会使用一个标准的 select 语句必要时一次加载数据。

    • 'joined' 告诉 SQLAlchemy 使用 JOIN 语句作为父级在同一查询中来加载关系。

    • 'subquery' 类似 'joined' ,但是 SQLAlchemy 会使用子查询。

    • 'dynamic' 在有多条数据的时候是特别有用的。不是直接加载这些数据,SQLAlchemy 会返回一个查询对象,在加载数据前您可以过滤(提取)它们。

    您如何为反向引用(backrefs)定义惰性(lazy)状态?使用 backref() 函数:

    <pre class="md-fences md-end-block" lang="" contenteditable="false" cid="n1092" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    addresses = db.relationship('Address',
    backref=db.backref('person', lazy='joined'), lazy='dynamic')</pre>

    多对多(many-to-many)关系

    如果您想要用多对多关系,您需要定义一个用于关系的辅助表。对于这个辅助表, 强烈建议 使用模型,而是采用一个实际的表:

    <pre class="md-fences md-end-block" lang="" contenteditable="false" cid="n1096" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">tags = db.Table('tags',
    db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),
    db.Column('page_id', db.Integer, db.ForeignKey('page.id'))
    )

    class Page(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    tags = db.relationship('Tag', secondary=tags,
    backref=db.backref('pages', lazy='dynamic'))

    class Tag(db.Model):
    id = db.Column(db.Integer, primary_key=True)</pre>

    这里我们配置 Page.tags 加载后作为标签的列表,因为我们并不期望每页出现太多的标签。而每个 tag 的页面列表( Tag.pages)是一个动态的反向引用。 正如上面提到的,这意味着您会得到一个可以发起 select 的查询对象。

    选择(Select),插入(Insert), 删除(Delete)

    现在您已经有了 declared models,是时候从数据库中查询数据。我们将会使用 快速入门章节中定义的数据模型。

    插入记录

    在查询数据之前我们必须先插入数据。您的所有模型都应该有一个构造函数,如果您 忘记了,请确保加上一个。只有您自己使用这些构造函数而 SQLAlchemy 在内部不会使用它, 所以如何定义这些构造函数完全取决与您。

    向数据库插入数据分为三个步骤:

    1. 创建 Python 对象

    2. 把它添加到会话

    3. 提交会话

    这里的会话不是 Flask 的会话,而是 Flask-SQLAlchemy 的会话。它本质上是一个 数据库事务的加强版本。它是这样工作的:

    <pre class="md-fences md-end-block" lang="shell" contenteditable="false" cid="n1133" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">>>> from yourapp import User

    me = User('admin', 'admin@example.com')
    db.session.add(me)
    db.session.commit()</pre>

    好吧,这不是很难吧。但是在您把对象添加到会话之前, SQLAlchemy 基本不考虑把它加到事务中。这是好事,因为您仍然可以放弃更改。比如想象 在一个页面上创建文章,但是您只想把文章传递给模板来预览渲染,而不是把它存进数据库。

    调用 add() 函数会添加对象。它会发出一个 INSERT 语句给数据库,但是由于事务仍然没有提交,您不会立即得到返回的 ID 。如果您提交,您的用户会有一个 ID:

    <pre class="md-fences md-end-block" lang="shell" contenteditable="false" cid="n1138" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">>>> me.id
    1</pre>

    删除记录

    删除记录是十分类似的,使用 delete() 代替 add():

    <pre class="md-fences md-end-block" lang="shell" contenteditable="false" cid="n1142" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">>>> db.session.delete(me)

    db.session.commit()</pre>

    查询记录

    那么我们怎么从数据库中查询数据?为此,Flask-SQLAlchemy 在您的 Model 类上提供了 query 属性。当您访问它时,您会得到一个新的所有记录的查询对象。在使用 all()或者 first() 发起查询之前可以使用方法 filter() 来过滤记录。如果您想要用主键查询的话,也可以使用 get()

    下面的查询假设数据库中有如下条目:

    <figure class="md-table-fig" contenteditable="false" cid="n1148" mdtype="table" style="box-sizing: border-box; margin: -8px 0px 0px -8px; overflow-x: auto; max-width: calc(100% + 16px); padding: 8px;">

    id username email
    1 admin admin@example.com
    2 peter peter@example.org
    3 guest guest@example.com

    </figure>

    通过用户名查询用户:

    <pre class="md-fences md-end-block" lang="shell" contenteditable="false" cid="n1167" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">>>> peter = User.query.filter_by(username='peter').first()

    peter.id
    1
    peter.email
    u'peter@example.org'</pre>

    同上但是查询一个不存在的用户名返回 None:

    <pre class="md-fences md-end-block" lang="shell" contenteditable="false" cid="n1170" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">>>> missing = User.query.filter_by(username='missing').first()

    missing is None
    True</pre>

    使用更复杂的表达式查询一些用户:

    <pre class="md-fences md-end-block" lang="shell" contenteditable="false" cid="n1173" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">>>> User.query.filter(User.email.endswith('@example.com')).all()
    [<User u'admin'>, <User u'guest'>]</pre>

    按某种规则对用户排序:

    <pre class="md-fences md-end-block" lang="shell" contenteditable="false" cid="n1176" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">>>> User.query.order_by(User.username)
    [<User u'admin'>, <User u'guest'>, <User u'peter'>]</pre>

    限制返回用户的数量:

    <pre class="md-fences md-end-block" lang="shell" contenteditable="false" cid="n1179" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">>>> User.query.limit(1).all()
    [<User u'admin'>]</pre>

    用主键查询用户:

    <pre class="md-fences md-end-block" lang="shell" contenteditable="false" cid="n1182" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">>>> User.query.get(1)
    <User u'admin'></pre>

    在视图中查询

    当您编写 Flask 视图函数,对于不存在的条目返回一个 404 错误是非常方便的。因为这是一个很常见的问题,Flask-SQLAlchemy 为了解决这个问题提供了一个帮助函数。可以使用 get_or_404() 来代替 get(),使用 first_or_404() 来代替 first()。这样会抛出一个 404 错误,而不是返回 None:

    <pre class="md-fences md-end-block" lang="python" contenteditable="false" cid="n1186" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 0.9em; white-space: pre; text-align: left; break-inside: avoid; display: block; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;">@app.route('/user/<username>')
    def show_user(username):
    user = User.query.filter_by(username=username).first_or_404()
    return render_template('show_user.html', user=user)</pre>

    相关文章

      网友评论

        本文标题:PyMySQL 和 SQLAlchemy使用

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