📜  用元数据描述数据库——SQLAlchemy

📅  最后修改于: 2022-05-13 01:54:51.113000             🧑  作者: Mango

用元数据描述数据库——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

输出:

访问列的名称(名称):

Python3

student_table.c.name.name

输出:

name

访问列的类型:

Python3

student_table.c.name.type

输出:

String(length=30)

获取表的主键:

Python3

student_table.primary_key

输出:

使用 MetaData 对象访问表和键

元数据对象可用于访问存储在元数据对象中的所有表,如下例所示:

访问元数据中的表:

Python3

metadata_object.tables

输出:

访问表的键:

Python3

metadata_object.tables.keys()

输出:

dict_keys(['student_account', 'items'])

声明约束

如您所见,我们已将第一个列声明为 student_table 中的主键。运行以下命令将显示主键约束的详细信息。

Python3

student_table.primary_key

输出:

主键约束通常是隐式声明的,而 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)

输出: