参考文章:
SQLAlchemy官方文档
https://docs.sqlalchemy.org/en/13/core/engines.html
https://docs.sqlalchemy.org/en/13/orm/mapping_styles.html#declarative-mapping
https://docs.sqlalchemy.org/en/13/core/metadata.html#column-table-metadata-api
https://docs.sqlalchemy.org/en/13/core/metadata.html#sqlalchemy.schema.MetaData.create_all
https://docs.sqlalchemy.org/en/13/orm/tutorial.html#building-a-relationship
Engine Configuration
数据库URL
这个create_engine()函数基于URL生成一个Engine。这些URL遵循RFC-1738,通常、包括用户名、密码、主机名、数据库名以及其他配置的可选关键字参数。在某些情况下,文件路径被接受,而在另一些情况下,“数据源名称”代替“主机”和“数据库”部分。数据库URL的典型形式是:
dialect+driver://username:password@host:port/database
方言(dialect)名称包括SQLAlchemy方言的标识名,如sqlite, mysql, postgresql, oracle,或mssql。DREVERNAME是使用所有小写字母连接到数据库的DBAPI的名称。如果未指定,则将导入“默认”DBAPI(如果可用)-此默认通常是该后端可用的最广为人知的驱动程序。
由于URL与任何其他URL一样,需要对密码中可能使用的特殊字符进行URL编码。下面是包含密码的URL示例"kx%jj5/g":
postgresql+pg8000://dbuser:kx%25jj5%2Fg@pghost10/appdb
可以使用以下方法生成上述密码的编码:urllib:
import urllib.parse
urllib.parse.quote_plus("kx%jj5/g")
'kx%25jj5%2Fg'
MySQL
MySQL¶
MySQL方言使用MySQLpython作为默认的DBAPI。有许多MySQLDBAPI可用,包括MySQL-连接器-python和OurSQL:
# default
engine = create_engine('mysql://scott:tiger@localhost/foo')
# mysqlclient (a maintained fork of MySQL-Python)
engine = create_engine('mysql+mysqldb://scott:tiger@localhost/foo')
# PyMySQL
engine = create_engine('mysql+pymysql://scott:tiger@localhost/foo')
create_engine()
sqlalchemy.create_engine(*args, **kwargs)
创建一个新的Engine实例。
标准的调用形式是将URL作为第一个位置参数发送,通常是指示数据库方言(dialect)和连接参数的字符串:
engine = create_engine("postgresql://scott:tiger@localhost/test")
然后,其他关键字参数可能会跟随它,从而建立对结果的各种选项。Engine及其底层Dialect和Pool结构:
engine = create_engine("mysql://scott:tiger@hostname/dbname",
encoding='latin1', echo=True)
URL的字符串形式是dialect[+driver] ?/user:password@host/dbname[?key=value…],dialect是数据库名,如mysql, oracle, postgresql等等,以及driver DBAPI的名称,如psycopg2, pyodbc, cx_oracle或者,URL可以是URL.
参数
case_sensitive=true
如果为false,结果列名将以不区分大小写的方式匹配,即,row[‘SomeColumn’].
echo=False
如果为True,则引擎将记录所有语句以及repr()将它们的参数列表设置为默认的日志处理程序,默认为sys.stdout用于输出。如果设置为字符串"debug",结果行也将打印到标准输出。这个echo属性Engine可以随时修改以打开或关闭日志记录;使用标准的Python logging 模块直接控制日志记录也是available的。
pool=None
一个已经被构造的Pool实例,如QueuePool。如果non-None,这个池将直接用作引擎的底层连接池,绕过URL参数中的任何连接参数。
pool_size=5
在连接池内保持打开的连接数,默认5。pool_size设置0表示无限制。
Declarative Mapping
声明映射¶
这个声明映射是在当前版本SQLAlchemy中构造映射的典型方式。利用Declarative system、用户定义类的组件以及Table将类映射到的元数据:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
fullname = Column(String)
nickname = Column(String)
上面是四列的基本单表映射。其他属性,例如与其他映射类的关系,也在类定义中被声明为内联:
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
fullname = Column(String)
nickname = Column(String)
addresses = relationship("Address", backref="user", order_by="Address.id")
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
user_id = Column(ForeignKey('user.id'))
email_address = Column(String)
这个声明映射系统在Object Relational Tutorial中被介绍
Column
参数
name–
数据库中表示的此列的名称。这个参数可以是第一个位置参数,也可以是通过关键字指定的。
不包含大写字符的名称将被视为不区分大小写的名称,除非它们是保留字,否则不会被引用。任何大写字符的名字都会被引用和发送。请注意,这种行为甚至适用于将大写名称标准化为不区分大小写的数据库,如Oracle。
type –
列的类型,使用一个子类表示TypeEngine…如果该类型不需要参数,也可以发送该类型的类,例如:
# use a type with arguments
Column('data', String(50))
# use no arguments
Column('level', Integer)
这个type参数可以是第二个位置参数或由关键字指定。
如果type是None或者省略,它将首先默认为特殊类型NullType。如果当Column设置为使用ForeignKey引用另一列时或ForeignKeyConstraint,远程引用列的类型也将复制到该列。
sqlalchemy常用数据类型:
Integer:整形。
Float:浮点类型。
Boolean:传递True/False进去。
DECIMAL:定点类型。
enum:枚举类型。
Date:传递datetime.date()进去。
DateTime:传递datetime.datetime()进去。
Time:传递datetime.time()进去。
String:字符类型,使用时需要指定长度,区别于Text类型。
Text:文本类型。
【参考自:https://blog.youkuaiyun.com/nunchakushuang/article/details/80392200】
autoincrement–
为整数主键列设置“自动增量”语义。默认值是字符串"auto"
default –
一个标量,Python可调用,或ColumnElement表示默认值对于该列
primary_key –
如果为True,则将此列标记为主键列。多个列可以设置此标志以指定复合主键。或者,可以通过显式的PrimaryKeyConstraint对象指定Table的主键。
index –
如果为True,则表示该列已编制索引。这是在表上使用索引构造的快捷方式。若要指定具有显式名称的索引或包含多个列的索引,请改用Index构造。
nullable –
当设置为false时,将导致在为列生成DDL时添加“not null”短语。当为True时,通常不会生成任何内容(在SQL中,此默认值为“null”),除非在某些非常特定的后端特定边缘情况下,“null”可能显式呈现。除非primary_key也是True,否则默认为True,在这种情况下,它默认为False。此参数仅在发出CREATE TABLE语句时使用。
create_all(bind=None, tables=None, checkfirst=True)
创建存储在此元数据中的所有表。
默认情况下,有条件的,不会尝试重新创建目标数据库中已存在的表。
参数
bind-用于访问数据库的可连接对象;如果没有,则使用此元数据上的现有绑定(如果有的话)。
tables-可选的表对象列表,它是元数据中全部表的子集(其他表被忽略)。
checkfirst-默认为True,不为目标数据库中已存在的表发出CREATE。
Build a Relationship
让我们考虑第二个表是如何关联到User,可以映射和查询。我们系统中的用户可以存储与其用户名相关的任意数量的电子邮件地址。这意味着从users到一个存储电子邮件地址的新表addresses中有一个一对多的联系。使用Declarative,我们定义这个表及其映射的类,Address:
>>> from sqlalchemy import ForeignKey
>>> from sqlalchemy.orm import relationship
>>> class Address(Base):
... __tablename__ = 'addresses'
... id = Column(Integer, primary_key=True)
... email_address = Column(String, nullable=False)
... user_id = Column(Integer, ForeignKey('users.id'))
...
... user = relationship("User", back_populates="addresses")
...
... def __repr__(self):
... return "<Address(email_address='%s')>" % self.email_address
>>> User.addresses = relationship(
... "Address", order_by=Address.id, back_populates="user")
上述类介绍了ForeignKey构造,它是应用于Column表示该列中的值应该是受约束为指定的远程列中的值。这是关系数据库的核心特性,也是将表的未连接集合转换为具有丰富的重叠关系的“胶水”。这个ForeignKey上面表示addresses.user_id列应被users.id列的值所约束,即其主键。
第二个指令,称为relationship(),告诉ORM Address类本身应该链接到User类,使用属性初始化Address.user. relationship()使用两个表之间的外键关系来确定此链接的性质,确定Address.user将是多对一。额外的relationship()指令放在User属性下的映射类User.addresses。两种relationship()指令,参数relationship.back_populates被指定为引用互补属性名称;通过这样做,每个relationship()可以对相同的反向关系做出明智的决定;一方面,Address.user指的是User实例,在另一边,User.addresses指的是Address实例。
注
这个relationship.back_populates参数是新版本一个非常常见的SQLAlchemy特性,名为relationship.backref。这个relationship.backref参数没有去任何地方,并将始终可用!这个relationship.back_populates是一个东西,只是更冗长,更容易操作。
多对一关系的反面总是一对多…一份完整的可用目录relationship()配置在基本关系模式.
两种互补关系Address.user和User.addresses被称为双向关系,并且是SQLAlchemyORM的一个关键特性。更多backref细节
论点relationship()如果使用声明式系统,则可以使用字符串指定与远程类有关的类。一旦所有映射都完成,这些字符串将被计算为Python表达式,以便生成实际的参数,在上面的例子中,User班级,等级。在此评估期间允许使用的名称包括,除其他外,根据声明的基创建的所有类的名称。
见docstring forrelationship()有关参数样式的更多细节。
你知道吗?
大多数(虽然不是所有)关系数据库中的外键约束只能链接到主键列或具有唯一约束的列。
引用多列主键并本身具有多列的外键约束称为“复合外键”。它还可以引用这些列的子集。
外键列可以自动更新自身,以响应引用列或行中的更改。这就是所谓的叶栅指称行为,是关系数据库的内置功能。
外键可以引用它自己的表。这被称为“自引用”外键。
Session
add(instance, _warn=True)
Place an object in the Session.
Its state will be persisted to the database on the next flush operation.
Repeated calls to add() will be ignored. The opposite of add() is expunge().
commit()
Flush pending changes and commit the current transaction.