Python全栈(七)Flask框架之7.ORM增删改查、数据类型和参数

一、Flask-ORM添加数据

先创建表:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE= 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)

class Article(Base):
    __tablename__ = 'article'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)

Base.metadata.create_all()

运行之后,会看到数据库中多了一个article表。
此时实例化一条数据并访问属性如下:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE= 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)

class Article(Base):
    __tablename__ = 'article'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)

# Base.metadata.create_all()
article = Article(name='Corley')
print(article.id)
print(article.name)

打印:

None
Corley

显然,此时name可以正常打印,但是id为None,这是因为id是一个自增的主键,还未插入到数据库表中,id不存在,所以为空。
将数据提交到数据库,需要使用Session对象
提交记录到数据库中:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE= 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)

class Article(Base):
    __tablename__ = 'article'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)

# Base.metadata.create_all()
article = Article(name='Corley')

# 保存数据到数据库中
Session = sessionmaker(bind=engine)
session = Session() # 含有__call__魔术方法,可以将Session类变成方法调用
# 添加数据
session.add(article)
# 提交数据
session.commit()
print(article.id)
print(article.name)

打印:

1
Corley

显然,此时得到了对应的id,再查看数据库article表,发现数据成功插入。
可以看出,把数据添加到session中之后,还要commit才能真正将数据保存到数据库,因为在SQLAlchemy的ORM实现中,在做commit操作之前,所有的操作都是在事务中进行的,因此如果要将事务中的操作真正映射到数据库中,还需要做commit操作
说明:
sessionmaker是一个类,实例化生成Session对象,因为sessionmaker类中有魔法方法__call__(),所以可以直接将对象调用,Session成了一个可调用对象,即把实例对象用类似函数的形式调用,模糊了函数和对象之间的概念。
添加多条数据:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE= 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)

class Article(Base):
    __tablename__ = 'article'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)

article1 = Article(name='Tony')
article2 = Article(name='Jack')

# 保存数据到数据库中
Session = sessionmaker(bind=engine)
session = Session()
# 添加数据
session.add_all([article1, article2])
# 提交数据
session.commit()

运行之后,查看数据库会发现又多了2条数据。

二、Flask-ORM数据的增删改查

先创建表:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE= 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)

class Blog(Base):
    __tablename__ = 'blog'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(String(500))
    author = Column(String(30))

Base.metadata.create_all()

运行后即创建表blog。
插入数据:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Blog(Base):
    __tablename__ = 'blog'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(String(500))
    author = Column(String(30))


# Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()


def add_data():
    blog = Blog(title='Python', content='人生苦短,我用Python', author='Jack')
    session.add(blog)
    session.commit()


if __name__ == '__main__':
    add_data()

运行即插入数据成功。
注意:
此时在实例化Blog对象时要显式传入参数,否则会报错,即Blog('Python', '人生苦短,我用Python', 'Jack')是会报错的。
查找操作是通过session.query()方法实现的,这个方法会返回一个Query对象,Query对象相当于一个数组,装载了查找出来的数据,并且可以进行迭代。
查询所有数据用all()方法,测试如下:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Blog(Base):
    __tablename__ = 'blog'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(String(500))
    author = Column(String(30))


# Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()


def add_data():
    blog = Blog(title='C', content='带你学C带你飞', author='Tom')
    session.add(blog)
    session.commit()


def search_data():
    data = session.query(Blog).all()
    for item in data:
        print(item.id, item.title, item.content, item.author)


def update_data():
    pass


if __name__ == '__main__':
    search_data()

打印:

1 Python 人生苦短,我用Python Jack
2 C 带你学C带你飞 Tom

显然,查询到所有数据。
还可以在定义模型时定义__str__()方法,从而可以自定义打印对象:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Blog(Base):
    __tablename__ = 'blog'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(String(500))
    author = Column(String(30))

    def __str__(self):
        return 'Blog(id:{}, title:{}, content:{}, author:{})'.format(self.id, self.title, self.content, self.author)


# Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()


def add_data():
    blog = Blog(title='C', content='带你学C带你飞', author='Tom')
    session.add(blog)
    session.commit()


def search_data():
    data = session.query(Blog).all()
    for item in data:
        print(item)


def update_data():
    pass


if __name__ == '__main__':
    search_data()

打印:

Blog(id:1, title:Python, content:人生苦短,我用Python, author:Jack)
Blog(id:2, title:C, content:带你学C带你飞, author:Tom)

还可以指定属性查询:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Blog(Base):
    __tablename__ = 'blog'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(String(500))
    author = Column(String(30))

    def __str__(self):
        return 'Blog(id:{}, title:{}, content:{}, author:{})'.format(self.id, self.title, self.content, self.author)


# Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()


def add_data():
    blog = Blog(title='C', content='带你学C带你飞', author='Tom')
    session.add(blog)
    session.commit()


def search_data():
    data = session.query(Blog.content, Blog.author).order_by(Blog.author)
    for item in data:
        print(item)


def update_data():
    pass


if __name__ == '__main__':
    search_data()

打印:

('人生苦短,我用Python', 'Foster')
('带你学C不带你飞', 'Tom')

显然,此时返回的是元组;
如果传递了两个或两个以上的对象,或者传递的是ORM类的属性,查找得到的结果就是元组。

可以对查询的结果切片,如下:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Blog(Base):
    __tablename__ = 'blog'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(String(500))
    author = Column(String(30))

    def __str__(self):
        return 'Blog(id:{}, title:{}, content:{}, author:{})'.format(self.id, self.title, self.content, self.author)


# Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()


def add_data():
    blog = Blog(title='C', content='带你学C带你飞', author='Tom')
    session.add(blog)
    session.commit()


def search_data():
    data = session.query(Blog.content)[1:]
    for item in data:
        print(item)


def update_data():
    pass


if __name__ == '__main__':
    search_data()

打印:

('带你学C不带你飞',)

如果要对结果进行过滤,可以使用filter()filter_by()两个方法。
这两个方法都是用来过滤的,区别在于,filter_by()传入的参数是关键字,filter()传入的参数是条件判断,能够传入的条件更多、更灵活。
filter()方法测试如下:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Blog(Base):
    __tablename__ = 'blog'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(String(500))
    author = Column(String(30))

    def __str__(self):
        return 'Blog(id:{}, title:{}, content:{}, author:{})'.format(self.id, self.title, self.content, self.author)


# Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()


def add_data():
    blog = Blog(title='C', content='带你学C带你飞', author='Tom')
    session.add(blog)
    session.commit()


def search_data():
    data = session.query(Blog).filter(Blog.title=='Python').all()
    for item in data:
        print(item)


def update_data():
    pass


if __name__ == '__main__':
    search_data()

打印:

Blog(id:1, title:Python, content:人生苦短,我用Python, author:Jack)

filter_by()方法使用示例如下:

def search_data():
    data = session.query(Blog).filter_by(title='C').all()
    for item in data:
        print(item)

这与前者的方法是等效的。

只查询第一条数据用first()方法,测试如下:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Blog(Base):
    __tablename__ = 'blog'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(String(500))
    author = Column(String(30))

    def __str__(self):
        return 'Blog(id:{}, title:{}, content:{}, author:{})'.format(self.id, self.title, self.content, self.author)


# Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()


def add_data():
    blog = Blog(title='C', content='带你学C带你飞', author='Tom')
    session.add(blog)
    session.commit()


def search_data():
    data = session.query(Blog).first()
    print(data)


def update_data():
    pass


if __name__ == '__main__':
    search_data()

打印:

Blog(id:1, title:Python, content:人生苦短,我用Python, author:Jack)

根据id指定查询数据用get()方法,传入的参数即为所需查询的数据对应的id,测试如下:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Blog(Base):
    __tablename__ = 'blog'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(String(500))
    author = Column(String(30))

    def __str__(self):
        return 'Blog(id:{}, title:{}, content:{}, author:{})'.format(self.id, self.title, self.content, self.author)


# Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()


def add_data():
    blog = Blog(title='C', content='带你学C带你飞', author='Tom')
    session.add(blog)
    session.commit()


def search_data():
    data = session.query(Blog).get(2)
    print(data)


def update_data():
    pass


if __name__ == '__main__':
    search_data()

打印:

Blog(id:2, title:C, content:带你学C带你飞, author:Tom)

显然,查询到的即为第2条数据。
如果get()方法传的参数不存在,会返回None。

修改数据时,直接调用对象属性并重新赋值即可,测试如下:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Blog(Base):
    __tablename__ = 'blog'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(String(500))
    author = Column(String(30))

    def __str__(self):
        return 'Blog(id:{}, title:{}, content:{}, author:{})'.format(self.id, self.title, self.content, self.author)


# Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()


def add_data():
    blog = Blog(title='C', content='带你学C带你飞', author='Tom')
    session.add(blog)
    session.commit()


def search_data():
    data = session.query(Blog).get(2)
    print(data)


def update_data():
    # 先查询数据
    blog = session.query(Blog).first()
    # 再修改数据
    blog.author = 'Foster'
    session.commit()
    print(blog)


if __name__ == '__main__':
    update_data()

打印:

Blog(id:1, title:Python, content:人生苦短,我用Python, author:Foster)

此时再查看数据库,数据也改变了。

删除数据用delete()方法:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Blog(Base):
    __tablename__ = 'blog'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(String(500))
    author = Column(String(30))

    def __str__(self):
        return 'Blog(id:{}, title:{}, content:{}, author:{})'.format(self.id, self.title, self.content, self.author)


# Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()


def add_data():
    blog = Blog(title='C', content='带你学C带你飞', author='Tom')
    session.add(blog)
    session.commit()


def search_data():
    data = session.query(Blog).all()
    for item in data:
        print(item)


def update_data():
    # 先查询数据
    blog = session.query(Blog).first()
    # 再修改数据
    blog.author = 'Foster'
    session.commit()
    print(blog)


def delete_data():
    blog = session.query(Blog).first()
    session.delete(blog)
    session.commit()
    search_data()


if __name__ == '__main__':
    delete_data()

打印:

Blog(id:5, title:C, content:带你学C不带你飞, author:Tom)

此时查看数据库表,发现一条数据已经删除,是永久地删除了这些数据。
但是在实际开发中一般不能直接删除数据,而是增加一个字段,比如is_delete字段来标记是否删除,值1表示已经删除,值0表示未删除,在查询的时候只查询is_delete字段值为0的数据即可。

如果需要恢复到修改之前的数据,需要用到回滚rollback(),测试如下:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Blog(Base):
    __tablename__ = 'blog'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(String(500))
    author = Column(String(30))

    def __str__(self):
        return 'Blog(id:{}, title:{}, content:{}, author:{})'.format(self.id, self.title, self.content, self.author)


# Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()


def add_data():
    blog = Blog(title='C', content='带你学C带你飞', author='Tom')
    session.add(blog)
    session.commit()


def search_data():
    data = session.query(Blog).all()
    for item in data:
        print(item)


def update_data():
    # 先查询数据
    blog = session.query(Blog).first()
    print(blog)
    # 再修改数据
    blog.author = 'Alan'
    print(blog)
    session.rollback()
    print(blog)
    session.commit()
    print(blog)


def delete_data():
    blog = session.query(Blog).get(3)
    session.delete(blog)
    session.commit()
    search_data()


if __name__ == '__main__':
    update_data()

打印:

Blog(id:3, title:Python, content:人生苦短,我用Python, author:Foster)
Blog(id:3, title:Python, content:人生苦短,我用Python, author:Alan)
Blog(id:3, title:Python, content:人生苦短,我用Python, author:Foster)
Blog(id:3, title:Python, content:人生苦短,我用Python, author:Foster)

显然,在回滚之后,数据又恢复到初始的状态,commit()之后数据也未发生变化,查看数据库中数据也未发生改变。

三、SQLAlchemy常用数据类型

sqlalchemy常用数据类型如下:

  • Integer
    整型。
  • Float
    浮点类型。
  • Boolean
    传递True/False进去。
  • DECIMAL
    定点类型,可以指定小数的位数和精度。
  • Enum
    枚举类型。
  • Date
    传递datetime.date()
  • Time
    传递datetime.time()
  • DateTime
    传递datetime.datetime()
  • String
    字符类型,使用时需要指定长度,区别于Text类型。
  • Text
    文本类型。
  • LONGTEXT
    长文本类型。

Float类型测试:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Book(Base):
    __tablename__ = 'book'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)
    price = Column(Float)



Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

book1 = Book(name='Python', price=12.34)
book2 = Book(name='Java', price=12.3456789)
session.add_all([book1, book2])
session.commit()

运行之后,查询数据库:

select * from book;

打印:

+----+--------+---------+
| id | name   | price   |
+----+--------+---------+
|  1 | Python |   12.34 |
|  2 | Java   | 12.3457 |
+----+--------+---------+
2 rows in set (0.00 sec)

显然,当小数位数较多时,只保留4位小数,损失了一部分精度。

DECIMAL类型测试如下:

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

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Book(Base):
    __tablename__ = 'book'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)
    price = Column(DECIMAL(20, 8))      # DECIMAL()的第一个参数为总位数,第二个参数为小数位数


# 删除表book以便重新创建
Base.metadata.drop_all()
Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

book1 = Book(name='Python', price=12.34)
book2 = Book(name='Java', price=12.3456789)
session.add_all([book1, book2])
session.commit()

运行后查询数据库:

+----+--------+-------------+
| id | name   | price       |
+----+--------+-------------+
|  1 | Python | 12.34000000 |
|  2 | Java   | 12.34567890 |
+----+--------+-------------+
2 rows in set (0.01 sec)

显然,此时数据精度更高,在对精度要求较高的情况下可以使用这种数据类型。

Boolean类型测试:

from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, DECIMAL, Boolean
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Book(Base):
    __tablename__ = 'book'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)
    price = Column(DECIMAL(20, 8))
    is_delete = Column(Boolean)


# 删除表book以便重新创建
Base.metadata.drop_all()
Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

book1 = Book(name='Python', price=12.34, is_delete=True)
book2 = Book(name='Java', price=12.3456789, is_delete=False)
session.add_all([book1, book2])
session.commit()

运行后查询数据库:

+----+--------+-------------+-----------+
| id | name   | price       | is_delete |
+----+--------+-------------+-----------+
|  1 | Python | 12.34000000 |         1 |
|  2 | Java   | 12.34567890 |         0 |
+----+--------+-------------+-----------+
2 rows in set (0.00 sec)

Enum类型测试:

from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, DECIMAL, Boolean, Enum
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Book(Base):
    __tablename__ = 'book'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)
    price = Column(DECIMAL(20, 8))
    is_delete = Column(Boolean)
    btype = Column(Enum('Science', 'Computer'))


# 删除表book以便重新创建
Base.metadata.drop_all()
Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

book1 = Book(name='Python', price=12.34, is_delete=True, btype='Science')
book2 = Book(name='Java', price=12.3456789, is_delete=False, btype='Computer')
session.add_all([book1, book2])
session.commit()

运行之后查询数据库:

+----+--------+-------------+-----------+----------+
| id | name   | price       | is_delete | btype    |
+----+--------+-------------+-----------+----------+
|  1 | Python | 12.34000000 |         1 | Science  |
|  2 | Java   | 12.34567890 |         0 | Computer |
+----+--------+-------------+-----------+----------+
2 rows in set (0.01 sec)

Datetime类型测试:

from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, DECIMAL, Boolean, Enum, DateTime
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime, timedelta

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Book(Base):
    __tablename__ = 'book'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)
    price = Column(DECIMAL(20, 8))
    is_delete = Column(Boolean)
    btype = Column(Enum('Science', 'Computer'))
    release_time = Column(DateTime)


# 删除表book以便重新创建
Base.metadata.drop_all()
Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

book1 = Book(name='Python', price=12.34, is_delete=True, btype='Science', release_time=datetime.now())
book2 = Book(name='Java', price=12.3456789, is_delete=False, btype='Computer', release_time=datetime.now() - timedelta(days=50))
session.add_all([book1, book2])
session.commit()

运行后查询数据库:

+----+--------+-------------+-----------+----------+---------------------+
| id | name   | price       | is_delete | btype    | release_time        |
+----+--------+-------------+-----------+----------+---------------------+
|  1 | Python | 12.34000000 |         1 | Science  | 2020-04-22 12:36:04 |
|  2 | Java   | 12.34567890 |         0 | Computer | 2020-03-03 12:36:04 |
+----+--------+-------------+-----------+----------+---------------------+
2 rows in set (0.01 sec)

Date类型和Time类型与DateTime类型用法类似。

LONGTEXT测试:
创建constants.py如下:

longtext_python = '''
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
'''

longtext_java = '''
Java is a technology for developing applications that makes the web more interesting and useful. Java is not the same as JavaScript, which is a simple technology for creating web pages and can only run in a browser.
With Java, you can play games, upload photos, chat online, participate in virtual experience, and use online training, online banking, interactive map and other services. If Java is not installed, many applications and websites will not work.
By default, Java will automatically notify you of new updates to install. To ensure the latest software and computer security, you must accept and install the update. If you have been notified to update Java on a Windows computer but you remember never downloading or installing it, it is possible that Java has been preloaded with your new computer.
'''

测试LONGTEXT代码如下:

from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, DECIMAL, Boolean, Enum, DateTime
from sqlalchemy.dialects.mysql import LONGTEXT
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime, timedelta
from constants import *

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Book(Base):
    __tablename__ = 'book'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)
    price = Column(DECIMAL(20, 8))
    is_delete = Column(Boolean)
    btype = Column(Enum('Science', 'Computer'))
    release_time = Column(DateTime)
    content = Column(LONGTEXT)


# 删除表book以便重新创建
Base.metadata.drop_all()
Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

book1 = Book(name='Python', price=12.34, is_delete=True, btype='Science', release_time=datetime.now(), content=longtext_python)
book2 = Book(name='Java', price=12.3456789, is_delete=False, btype='Computer', release_time=datetime.now() - timedelta(days=50), content=longtext_java)
session.add_all([book1, book2])
session.commit()

运行后,查询数据库:

+----+--------+-------------+-----------+----------+---------------------+----------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------+                               
| id | name   | price       | is_delete | btype    | release_time        | content                                                        
                                                                                                                                          
                                                                                                                                          
                                                                                                                                          
                                                                                                                                          
                                                                                                                                          
                                                                                                          |                               
+----+--------+-------------+-----------+----------+---------------------+----------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------+                               
|  1 | Python | 12.34000000 |         1 | Science  | 2020-04-22 17:44:40 |                                                                
The Zen of Python, by Tim Peters                                                                                                          
                                                                                                                                          
Beautiful is better than ugly.                                                                                                            
Explicit is better than implicit.                                                                                                         
Simple is better than complex.                                                                                                            
Complex is better than complicated.                                                                                                       
Flat is better than nested.                                                                                                               
Sparse is better than dense.                                                                                                              
Readability counts.                                                                                                                       
Special cases aren't special enough to break the rules.                                                                                   
Although practicality beats purity.                                                                                                       
Errors should never pass silently.                                                                                                        
Unless explicitly silenced.                                                                                                               
In the face of ambiguity, refuse the temptation to guess.                                                                                 
There should be one-- and preferably only one --obvious way to do it.                                                                     
Although that way may not be obvious at first unless you're Dutch.                                                                        
Now is better than never.                                                                                                                 
Although never is often better than *right* now.                                                                                          
If the implementation is hard to explain, it's a bad idea.                                                                                
If the implementation is easy to explain, it may be a good idea.                                                                          
Namespaces are one honking great idea -- let's do more of those!                                                                          
 |                                                                                                                                        
|  2 | Java   | 12.34567890 |         0 | Computer | 2020-03-03 17:44:40 |                                                                
Java is a technology for developing applications that makes the web more interesting and useful. Java is not the same as JavaScript, which
 is a simple technology for creating web pages and can only run in a browser.                                                             
With Java, you can play games, upload photos, chat online, participate in virtual experience, and use online training, online banking, int
eractive map and other services. If Java is not installed, many applications and websites will not work.                                  
By default, Java will automatically notify you of new updates to install. To ensure the latest software and computer security, you must ac
cept and install the update. If you have been notified to update Java on a Windows computer but you remember never downloading or installi
ng it, it is possible that Java has been preloaded with your new computer.                                                                
                                                |                                                                                         
+----+--------+-------------+-----------+----------+---------------------+----------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------+                               
2 rows in set (0.00 sec)                                                                                                                  
                                                                                                                                          

四、Column常用参数和query可用参数

1.Column常用参数

常用参数如下:

  • default
    默认值。
  • nullable
    是否可空。
  • primary_key
    是否为主键。
  • unique
    是否唯一。
  • autoincrement
    是否自动增长。
  • onupdate
    指定在更新数据的时候执行的函数。
  • name
    该属性在数据库中的字段映射。

onupdate测试如下:

from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, DECIMAL, Boolean, Enum, DateTime
from sqlalchemy.dialects.mysql import LONGTEXT
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime, timedelta

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Book(Base):
    __tablename__ = 'book'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)
    price = Column(DECIMAL(20, 8))
    is_delete = Column(Boolean)
    btype = Column(Enum('Science', 'Computer'))
    release_time = Column(DateTime)
    update_time = Column(DateTime, onupdate=datetime.now())


# 删除表book以便重新创建
Base.metadata.drop_all()
Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

book1 = Book(name='Python', price=12.34, is_delete=True, btype='Science', release_time=datetime.now(), content=longtext_python)
book2 = Book(name='Java', price=12.3456789, is_delete=False, btype='Computer', release_time=datetime.now() - timedelta(days=50), content=longtext_java)
session.add_all([book1, book2])
session.commit()

运行后查询数据库:

+----+--------+-------------+-----------+----------+---------------------+-------------+ 
| id | name   | price       | is_delete | btype    | release_time        | update_time | 
+----+--------+-------------+-----------+----------+---------------------+-------------+ 
|  1 | Python | 12.34000000 |         1 | Science  | 2020-04-22 18:01:12 | NULL        | 
|  2 | Java   | 12.34567890 |         0 | Computer | 2020-03-03 18:01:12 | NULL        | 
+----+--------+-------------+-----------+----------+---------------------+-------------+ 
2 rows in set (0.00 sec)                                                                 

显然,此时update_time字段的值为空,改变数据:

from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, DECIMAL, Boolean, Enum, DateTime
from sqlalchemy.dialects.mysql import LONGTEXT
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime, timedelta

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Book(Base):
    __tablename__ = 'book'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)
    price = Column(DECIMAL(20, 8))
    is_delete = Column(Boolean)
    btype = Column(Enum('Science', 'Computer'))
    release_time = Column(DateTime)
    update_time = Column(DateTime, onupdate=datetime.now())


Session = sessionmaker(bind=engine)
session = Session()

book = session.query(Book).first()
print(book.name)
book.name = 'PHP'
print(book.name)
session.commit()

此时修改了数据,打印:

Python
PHP

再查询数据库:

+----+------+-------------+-----------+----------+---------------------+---------------------+
| id | name | price       | is_delete | btype    | release_time        | update_time         |
+----+------+-------------+-----------+----------+---------------------+---------------------+
|  1 | PHP  | 12.34000000 |         1 | Science  | 2020-04-22 18:01:12 | 2020-04-22 18:05:13 |
|  2 | Java | 12.34567890 |         0 | Computer | 2020-03-03 18:01:12 | NULL                |
+----+------+-------------+-----------+----------+---------------------+---------------------+
2 rows in set (0.01 sec)

显然,此时第一条数据发生改变,同时update_time字段的值也为时间,不再为空。
除了上述用法,还可以直接给onupdate传递一个函数,在修改记录时会调用这个函数。

在定义模型类时,默认情况下定义的属性名称即为数据库表中的字段名,也可以通过name参数来指定在数据库表中的字段名,如下:

from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, DECIMAL, Boolean, Enum, DateTime
from sqlalchemy.dialects.mysql import LONGTEXT
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime, timedelta

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Book(Base):
    __tablename__ = 'book'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)
    price = Column(DECIMAL(20, 8))
    is_delete = Column(Boolean)
    btype = Column(Enum('Science', 'Computer'))
    release_time = Column(DateTime)
    update_time = Column('Last_Updated', DateTime, onupdate=datetime.now())


# 删除表book以便重新创建
Base.metadata.drop_all()
Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

book1 = Book(name='Python', price=12.34, is_delete=True, btype='Science', release_time=datetime.now())
book2 = Book(name='Java', price=12.3456789, is_delete=False, btype='Computer', release_time=datetime.now() - timedelta(days=50))
session.add_all([book1, book2])
session.commit()

运行后查询数据库:

+----+--------+-------------+-----------+----------+---------------------+--------------+
| id | name   | price       | is_delete | btype    | release_time        | Last_Updated |
+----+--------+-------------+-----------+----------+---------------------+--------------+
|  1 | Python | 12.34000000 |         1 | Science  | 2020-04-22 18:13:12 | NULL         |
|  2 | Java   | 12.34567890 |         0 | Computer | 2020-03-03 18:13:12 | NULL         |
+----+--------+-------------+-----------+----------+---------------------+--------------+
2 rows in set (0.01 sec)

可以看到,update_time字段改成了Last_Updated字段。

2.query可用参数

模型对象

指定查找这个模型中所有的对象。
测试如下:
创建表并插入数据:

from datetime import datetime, timedelta
from sqlalchemy import Column, Integer, String, Float
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from random import randint

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Book(Base):
    __tablename__ = 'book'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)
    price = Column(Float)

    def __str__(self):
        return 'Book(id:{}, name:{}, price:{})'.format(self.id, self.name, self.price)


# 删除表book以便重新创建
Base.metadata.drop_all()
Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

for i in range(10):
    book = Book(name='Name %d' % (i + 1), price=randint(1, 50))
    session.add(book)

session.commit()

运行后查询数据库得:

+----+---------+-------+ 
| id | name    | price | 
+----+---------+-------+ 
|  1 | Name 1  |    45 | 
|  2 | Name 2  |    49 | 
|  3 | Name 3  |    14 | 
|  4 | Name 4  |    16 | 
|  5 | Name 5  |    17 | 
|  6 | Name 6  |     3 | 
|  7 | Name 7  |    25 | 
|  8 | Name 8  |    16 | 
|  9 | Name 9  |    32 | 
| 10 | Name 10 |    22 | 
+----+---------+-------+ 
10 rows in set (0.01 sec)

打印模型对象需要在模型中实现__str__()方法,测试如下:

from datetime import datetime, timedelta
from sqlalchemy import Column, Integer, String, Float
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from random import randint

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Book(Base):
    __tablename__ = 'book'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)
    price = Column(Float)

    def __str__(self):
        return 'Book(id:{}, name:{}, price:{})'.format(self.id, self.name, self.price)


# 删除表book以便重新创建
Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

books = session.query(Book).all()
for book in books:
    print(book)

session.commit()

打印:

Book(id:1, name:Name 1, price:45.0)
Book(id:2, name:Name 2, price:49.0)
Book(id:3, name:Name 3, price:14.0)
Book(id:4, name:Name 4, price:16.0)
Book(id:5, name:Name 5, price:17.0)
Book(id:6, name:Name 6, price:3.0)
Book(id:7, name:Name 7, price:25.0)
Book(id:8, name:Name 8, price:16.0)
Book(id:9, name:Name 9, price:32.0)
Book(id:10, name:Name 10, price:22.0)

模型属性

可以指定只查找模型中的某几个属性。
打印对象属性测试如下:

from datetime import datetime, timedelta
from sqlalchemy import Column, Integer, String, Float
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from random import randint

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Book(Base):
    __tablename__ = 'book'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)
    price = Column(Float)

    def __str__(self):
        return 'Book(id:{}, name:{}, price:{})'.format(self.id, self.name, self.price)


# 删除表book以便重新创建
# Base.metadata.drop_all()
Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

# for i in range(10):
#     book = Book(name='Name %d' % (i + 1), price=randint(1, 50))
#     session.add(book)

books = session.query(Book).all()
for book in books:
    print(book.id, book.name, book.price)

session.commit()

打印:

1 Name 1 45.0
2 Name 2 49.0
3 Name 3 14.0
4 Name 4 16.0
5 Name 5 17.0
6 Name 6 3.0
7 Name 7 25.0
8 Name 8 16.0
9 Name 9 32.0
10 Name 10 22.0

聚合函数

  • func.count
    统计行的数量。
  • func.avg
    求平均值。
  • func.max
    求最大值。
  • func.min
    求最小值。
  • func.sum
    求和。

count计数测试:

from sqlalchemy import Column, Integer, String, Float
from sqlalchemy import create_engine, func
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Book(Base):
    __tablename__ = 'book'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)
    price = Column(Float)

    def __str__(self):
        return 'Book(id:{}, name:{}, price:{})'.format(self.id, self.name, self.price)


# 删除表book以便重新创建
Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

result = session.query(func.count(Book.id)).first()
print(result)

打印:

(10,)

得到了记录条数。

avg平均值测试:

from sqlalchemy import Column, Integer, String, Float
from sqlalchemy import create_engine, func
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Book(Base):
    __tablename__ = 'book'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)
    price = Column(Float)

    def __str__(self):
        return 'Book(id:{}, name:{}, price:{})'.format(self.id, self.name, self.price)


# 删除表book以便重新创建
Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

result = session.query(func.avg(Book.price)).first()
print(result)

打印:

(23.9,)

max最大值和min最小值测试:

from sqlalchemy import Column, Integer, String, Float
from sqlalchemy import create_engine, func
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Book(Base):
    __tablename__ = 'book'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)
    price = Column(Float)

    def __str__(self):
        return 'Book(id:{}, name:{}, price:{})'.format(self.id, self.name, self.price)


# 删除表book以便重新创建
Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

result1 = session.query(func.max(Book.price)).first()
result2 = session.query(func.min(Book.price)).first()
print(result1, result2)

打印:

(49.0,) (3.0,)

sum求和测试:

from sqlalchemy import Column, Integer, String, Float
from sqlalchemy import create_engine, func
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# 数据库连接配置
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'
DATABASE = 'flask_demo'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Book(Base):
    __tablename__ = 'book'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)
    price = Column(Float)

    def __str__(self):
        return 'Book(id:{}, name:{}, price:{})'.format(self.id, self.name, self.price)


# 删除表book以便重新创建
Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

result = session.query(func.sum(Book.price)).first()
print(result)

打印:

(239.0,)
发布了120 篇原创文章 · 获赞 1248 · 访问量 31万+

猜你喜欢

转载自blog.csdn.net/CUFEECR/article/details/105691346
今日推荐