用元数据描述数据库——SQLAlchemy
在本文中,我们将了解如何在Python中使用 SQLAlchemy 描述具有元数据的数据库。
数据库元数据用Python数据结构来描述数据库的结构。数据库通常由表和列组成。数据库元数据服务于我们生成 SQL 查询和对象关系映射。它帮助我们生成模式。数据库元数据最基本的对象是元数据、表和列。
用元数据描述数据库:SQLAlchemy Core
使用 Table 对象设置 MetaData:
关系数据库中的查询通常是在数据库的表上创建的。这些表在Python SQLAlchemy 中表示为 Table 对象,名为Table。 MetaData是一个对象,它由以字符串名称为键的 Table 对象组成。创建 MetaData 对象的语法如下:
from sqlalchemy import MetaData
metadata_obj=MetaData()
单个 MetaData 对象足以满足整个应用程序。创建 MetaData 对象后,我们可以声明 Table 对象。让我们看一个为学生帐户创建表的示例,该表由 -name、age 和grade 列组成,我们还添加了一个 id 作为主键。
我们现在使用 MetaData 对象将上表转换为 Schema。
Python3
from sqlalchemy import MetaData
from sqlalchemy import Integer, String, Column, Table
metadata_object=MetaData()
student_table = Table(
"student_account",
metadata_object,
Column('id', Integer, primary_key=True),
Column('name', String(30)),
Column('age',Integer),
Column('grade', String(80))
)
Python3
from sqlalchemy import create_engine
from sqlalchemy import DateTime, Numeric, Enum
item_detail = Table(
"items",
metadata_object,
Column("key", String(50), primary_key=True),
Column("timestamp", DateTime),
Column("price", Numeric(100, 2)),
Column("type", Enum("dry", "wet")),
)
# creating an engine object
engine = create_engine("sqlite+pysqlite:///:memory:",
echo=True, future=True)
# emitting DDL
metadata_object.create_all(engine)
Python3
student_table.name
Python3
student_table.c.name
Python3
student_table.c.name.name
Python3
student_table.c.name.type
Python3
student_table.primary_key
Python3
metadata_object.tables
Python3
metadata_object.tables.keys()
Python3
student_table.primary_key
Python3
from sqlalchemy import ForeignKey
address_table = Table(
"address",
metadata_object,
Column('id', Integer, primary_key=True),
Column('student_id', ForeignKey('student_account.id'), nullable=False),
Column('email_address', String, nullable=False)
)
Python3
from sqlalchemy import create_engine
# creating an engine object
engine = create_engine("sqlite+pysqlite:///:memory:",
echo=True, future=True)
# emitting DDL
metadata_object.create_all(engine)
Python
from sqlalchemy import create_engine
# creating an engine object
engine = create_engine("sqlite+pysqlite:///:memory:",
echo=True, future=True)
# emitting DDL
metadata_object.drop_all(engine)
Python3
from sqlalchemy.orm import registry
mapper_registry = registry()
mapper_registry.metadata
Python3
Base = mapper_registry.generate_base()
Python3
from sqlalchemy.orm import relationship
class Student(Base):
__tablename__ = 'student_account'
id = Column(Integer, primary_key=True)
name = Column(String(30))
age = Column(Integer)
grade = Column(String)
addresses = relationship("Address", back_populates="student")
def __repr__(self):
return f"Student(id={self.id!r}, name={self.name!r},\
age={self.age!r},grade={self.grade!r})"
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
email_address = Column(String, nullable=False)
student_id = Column(Integer, ForeignKey('student_account.id'))
student = relationship("Student", back_populates="addresses")
def __repr__(self):
return f"Address(id={self.id!r}, email_address={self.email_address!r})"
Python3
Student.__table__
Python3
Address.__table__
Python3
mapper_registry.metadata.create_all(engine)
Base.metadata.create_all(engine)
Python3
metadata2=MetaData()
with engine.connect() as conn:
student_reflected=Table("student_account",
metadata2,
autoload_with=conn)
Python3
print(student_reflected.c)
print(student_reflected.primary_key)
在上面的代码中,A Table 表示一个将自身分配给 MetaData 对象的数据库表
Column 表示将自身分配给 Table 对象的 Table 的 Column。 Column 通常包含一个字符串名称和一个类型对象,例如 Integer、String 等。
创建具有不同数据类型的表
Python3
from sqlalchemy import create_engine
from sqlalchemy import DateTime, Numeric, Enum
item_detail = Table(
"items",
metadata_object,
Column("key", String(50), primary_key=True),
Column("timestamp", DateTime),
Column("price", Numeric(100, 2)),
Column("type", Enum("dry", "wet")),
)
# creating an engine object
engine = create_engine("sqlite+pysqlite:///:memory:",
echo=True, future=True)
# emitting DDL
metadata_object.create_all(engine)
访问表和列
Table 的列通常存储在关联数组中,即Table.c ,并且可以使用“c”访问,如下例所示。
获取表名:
Python3
student_table.name
输出:
'student_account'
使用运算符c 访问列:
Python3
student_table.c.name
输出:
Column(‘name’, String(length=30), table=
访问列的名称(名称):
Python3
student_table.c.name.name
输出:
name
访问列的类型:
Python3
student_table.c.name.type
输出:
String(length=30)
获取表的主键:
Python3
student_table.primary_key
输出:
PrimaryKeyConstraint(Column(‘id’, Integer(), table=
使用 MetaData 对象访问表和键
元数据对象可用于访问存储在元数据对象中的所有表,如下例所示:
访问元数据中的表:
Python3
metadata_object.tables
输出:
FacadeDict({‘student_account’: Table(‘student_account’, MetaData(), Column(‘id’, Integer(), table=
访问表的键:
Python3
metadata_object.tables.keys()
输出:
dict_keys(['student_account', 'items'])
声明约束
如您所见,我们已将第一个列声明为 student_table 中的主键。运行以下命令将显示主键约束的详细信息。
Python3
student_table.primary_key
输出:
PrimaryKeyConstraint(Column(‘id’, Integer(), table=
主键约束通常是隐式声明的,而 ForeignKeyConstraint 是显式声明的。如果两个表通过对象 ForeignKey 相互关联,我们使用外键约束。
让我们创建一个名为 address_table 的新表,其中包含学生的电子邮件地址,我们将有一个引用学生表的外键约束。
Python3
from sqlalchemy import ForeignKey
address_table = Table(
"address",
metadata_object,
Column('id', Integer, primary_key=True),
Column('student_id', ForeignKey('student_account.id'), nullable=False),
Column('email_address', String, nullable=False)
)
创建和删除表
创建表:
到目前为止,我们已经创建了两个带有一组列和约束的表。接下来是我们必须将 DDL 发送到 SQLite 数据库(在这种情况下),以便我们可以查询表。这可以如下所示完成:
Python3
from sqlalchemy import create_engine
# creating an engine object
engine = create_engine("sqlite+pysqlite:///:memory:",
echo=True, future=True)
# emitting DDL
metadata_object.create_all(engine)
输出:
丢弃表
drop_all()方法用于删除元数据对象中的所有表。
Python
from sqlalchemy import create_engine
# creating an engine object
engine = create_engine("sqlite+pysqlite:///:memory:",
echo=True, future=True)
# emitting DDL
metadata_object.drop_all(engine)
输出:
用元数据描述数据库:SQLAlchemy ORM
我们将学习如何创建与使用 Core 和 ORM 创建的表相同的表。 ORM 由映射类组成。映射类的声明方式与创建任何Python类的方式相同,我们将映射类的属性链接到表的列。
在 ORM 中,MetaData 对象与称为 Registry 的 ORM-Only 对象组合在一起。我们构建 Registry 如下所示:
Python3
from sqlalchemy.orm import registry
mapper_registry = registry()
mapper_registry.metadata
输出:
MetaData()
在 ORM 中,我们不是直接声明 Table 对象,而是使用映射类来间接声明它们。映射的类从称为声明基的基本目录下降。可以使用 registry.generate_base() 方法使用注册表创建声明性基础。
Python3
Base = mapper_registry.generate_base()
这个基类作为我们声明的 ORM 映射类的基类。可以使用 ORM 创建两个表 Student_account 和 address ,如下所示。
Python3
from sqlalchemy.orm import relationship
class Student(Base):
__tablename__ = 'student_account'
id = Column(Integer, primary_key=True)
name = Column(String(30))
age = Column(Integer)
grade = Column(String)
addresses = relationship("Address", back_populates="student")
def __repr__(self):
return f"Student(id={self.id!r}, name={self.name!r},\
age={self.age!r},grade={self.grade!r})"
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
email_address = Column(String, nullable=False)
student_id = Column(Integer, ForeignKey('student_account.id'))
student = relationship("Student", back_populates="addresses")
def __repr__(self):
return f"Address(id={self.id!r}, email_address={self.email_address!r})"
.__table__ 属性用于查看从声明性映射类创建的 Table 对象,如下所示:
Python3
Student.__table__
输出:
Table('student_account', MetaData(), Column('id', Integer(),
table=, primary_key=True, nullable=False),
Column('name', String(length=30), table=),
Column('age', Integer(), table=),
Column('grade', String(), table=), schema=None)
Python3
Address.__table__
输出:
Table('address', MetaData(), Column('id', Integer(),
table=, primary_key=True, nullable=False),
Column('email_address', String(), table=,
nullable=False), Column('student_id', Integer(),
ForeignKey('student_account.id'), table=), schema=None)
发出 DDL:
在 ORM 中,为了发出 DDL,我们使用与我们的注册表和 ORM 声明性基类关联的 MetaData 对象。
Python3
mapper_registry.metadata.create_all(engine)
Base.metadata.create_all(engine)
输出:
表反射
“反射”是指基于从现有表中读取来加载表对象。例如,我们将创建一个新的 Table 对象,它代表我们在本文前面部分手动创建的 student_account 对象,如下所示。
Python3
metadata2=MetaData()
with engine.connect() as conn:
student_reflected=Table("student_account",
metadata2,
autoload_with=conn)
输出:
您现在可以访问我们刚刚创建的反射表的列,如下所示:
Python3
print(student_reflected.c)
print(student_reflected.primary_key)
输出:
ImmutableColumnCollection(student_account.id, student_account.name, student_account.age, student_account.grade)
PrimaryKeyConstraint(Column(‘id’, INTEGER(), table=