8.24. SQLAlchemy Schema Metadata
8.24.1. Use Case - 1
from sqlalchemy import MetaData
from sqlalchemy import Table, Column
from sqlalchemy import Integer, String
from sqlalchemy import select
metadata = MetaData()
users = Table('users', metadata,
Column('id', Integer, primary_key=True),
Column('firstname', String(50), nullable=False),
Column('lastname', String(50), nullable=False),
)
users
Table('users', MetaData(), Column('id', Integer(), table=<users>,
primary_key=True, nullable=False), Column('firstname', String(length=50),
table=<users>, nullable=False), Column('lastname', String(length=50),
table=<users>, nullable=False), schema=None)
users.name
'users'
users.primary_key
PrimaryKeyConstraint(Column('id', Integer(), table=<users>, primary_key=True, nullable=False))
Associative array of columns. Bit looking like a dict, but not quite.
users.c
<sqlalchemy.sql.base.ImmutableColumnCollection object at 0x...>
users.c.values()
[Column('id', Integer(), table=<users>, primary_key=True, nullable=False),
Column('firstname', String(length=50), table=<users>, nullable=False),
Column('lastname', String(length=50), table=<users>, nullable=False)]
You can query each column separately about all metadata:
users.c.firstname
Column('firstname', String(length=50), table=<users>, nullable=False)
users.c.firstname.name
'firstname'
users.c.firstname.type
String(length=50)
Table metadata is used to generate SQL statements:
print(select(users))
SELECT users.id, users.firstname, users.lastname
FROM users
8.24.2. Schema Generation
Table and MetaData objects can be used to generate a schema in database;
MetaData features the create_all()
method. [1]
from sqlalchemy import create_engine
DATABASE = 'sqlite:///:memory:'
engine = create_engine(DATABASE)
with engine.begin() as db:
metadata.create_all(db)
8.24.3. Use Case - 1
SQLite does not have Enums
from sqlalchemy import MetaData
from sqlalchemy import create_engine
from sqlalchemy import Table, Column
from sqlalchemy import Integer, String, Date, Numeric, Enum
DATABASE = 'sqlite:///:memory:'
engine = create_engine(DATABASE)
metadata = MetaData()
astronaut = Table('astronaut', metadata,
Column('id', Integer, primary_key=True),
Column('firstname', String(50), nullable=False),
Column('lastname', String(50), nullable=False),
Column('birthdate', Date),
Column('height', Integer),
Column('weight', Numeric(3,2)),
Column('agency', Enum('NASA', 'ESA', 'POLSA')),
)
with engine.begin() as db:
astronaut.create(db)
metadata.tables.keys()
dict_keys(['astronaut'])
metadata.tables['astronaut']
Table('astronaut', MetaData(),
Column('id', Integer(), table=<astronaut>, primary_key=True, nullable=False),
Column('firstname', String(length=50), table=<astronaut>, nullable=False),
Column('lastname', String(length=50), table=<astronaut>, nullable=False),
Column('birthdate', Date(), table=<astronaut>),
Column('height', Integer(), table=<astronaut>),
Column('weight', Numeric(precision=3, scale=2), table=<astronaut>),
Column('agency', Enum('NASA', 'ESA', 'POLSA'), table=<astronaut>), schema=None)
8.24.4. Use Case - 2
Table metadata also allows for constraints and indexes. ForeignKey
is used to link one column to a remote primary key. Note we can omit
the datatype for a ForeignKey
column [1].
from sqlalchemy import MetaData
from sqlalchemy import create_engine
from sqlalchemy import Table, Column
from sqlalchemy import Integer, String, Date, Numeric, Enum, ForeignKey
DATABASE = 'sqlite:///:memory:'
engine = create_engine(DATABASE)
metadata = MetaData()
astronauts = Table('astronauts', metadata,
Column('id', Integer, primary_key=True),
Column('firstname', String(50), nullable=False),
Column('lastname', String(50), nullable=False),
Column('birthdate', Date),
Column('height', Integer),
Column('weight', Numeric(3,2)),
Column('agency', Enum('NASA', 'ESA', 'POLSA')),
)
missions = Table('missions', metadata,
Column('id', Integer, primary_key=True),
Column('astronaut_id', ForeignKey('astronauts.id'), nullable=False),
Column('year', Integer, nullable=False),
Column('name', String(100), nullable=False),
)
with engine.begin() as db:
astronauts.create(db)
missions.create(db)
8.24.5. Use Case - 3
ForeignKey
is a shortcut for ForeignKeyConstraint
which should be
used for composite references. [1]
from sqlalchemy import ForeignKeyConstraint
from sqlalchemy import Table, Column
from sqlalchemy import Text, Integer, String, Date
DATABASE = 'sqlite:///:memory:'
engine = create_engine(DATABASE)
metadata = MetaData()
story_table = Table('story', metadata,
Column('story_id', Integer, primary_key=True),
Column('version_id', Integer, primary_key=True),
Column('headline', String(100), nullable=False),
Column('body', Text),
)
published_table = Table('published', metadata,
Column('pub_id', Integer, primary_key=True),
Column('pub_timestamp', Date, nullable=True),
Column('story_id', Integer),
Column('version_id', Integer),
ForeignKeyConstraint(
['story_id', 'version_id'],
['story.story_id', 'story.version_id'],
),
)
create_all()
by default checks for tables existing already.
with engine.begin() as db:
metadata.create_all(db)