SQLAlchemy Generator#

BESSER provides a code generator that creates SQLAlchemy models to define the structure of a relational database. This structure (known as Declarative Mapping) defines the database metadata (using a Python object model) that will represent the input structural B-UML model.

Now, let’s generate the code for SQLAlchemy of our Structural model example. For this, you should create the generator, provide the Structural model, and use the generate method as follows:

from besser.generators.sql_alchemy import SQLAlchemyGenerator

generator: SQLAlchemyGenerator = SQLAlchemyGenerator(model=library_model)
generator.generate(dbms="sqlite")

The dbms parameter specifies the target database management system. In this example, we use sqlite, but you can also specify postgresql, mysql, mssql, or mariadb.

Generated Output#

The sql_alchemy.py file will be generated inside the <<current_directory>>/output folder and it will look as follows.

 1import enum
 2from typing import List, Optional
 3from sqlalchemy import (
 4    create_engine, Column, ForeignKey, Table, Text, Boolean, String, Date, 
 5    Time, DateTime, Float, Integer, Enum
 6)
 7from sqlalchemy.orm import (
 8    column_property, DeclarativeBase, Mapped, mapped_column, relationship
 9)
10from datetime import datetime, time, date
11
12class Base(DeclarativeBase):
13    pass
14
15
16
17# Tables definition for many-to-many relationships
18book_author_assoc = Table(
19    "book_author_assoc",
20    Base.metadata,
21    Column("writtenBy", ForeignKey("author.id"), primary_key=True),
22    Column("publishes", ForeignKey("book.id"), primary_key=True),
23)
24
25# Tables definition
26class Author(Base):
27    __tablename__ = "author"
28    id: Mapped[int] = mapped_column(primary_key=True)
29    name: Mapped[str] = mapped_column(String(100))
30    email: Mapped[str] = mapped_column(String(100))
31
32class Book(Base):
33    __tablename__ = "book"
34    id: Mapped[int] = mapped_column(primary_key=True)
35    title: Mapped[str] = mapped_column(String(100))
36    pages: Mapped[int] = mapped_column(Integer)
37    release: Mapped[date] = mapped_column(Date)
38
39class Library(Base):
40    __tablename__ = "library"
41    id: Mapped[int] = mapped_column(primary_key=True)
42    address: Mapped[str] = mapped_column(String(100))
43    name: Mapped[str] = mapped_column(String(100))
44
45
46#--- Foreign keys and relationships of the author table
47Author.publishes: Mapped[List["Book"]] = relationship("Book", secondary=book_author_assoc, back_populates="writtenBy")
48
49#--- Foreign keys and relationships of the book table
50Book.writtenBy: Mapped[List["Author"]] = relationship("Author", secondary=book_author_assoc, back_populates="publishes")
51Book.locatedIn: Mapped["Library"] = mapped_column(ForeignKey("library.id"), nullable=False)
52
53#--- Foreign keys and relationships of the library table
54Library.has: Mapped[List["Book"]] = relationship("Book", back_populates="locatedIn")
55
56# Database connection
57
58DATABASE_URL = "sqlite:///LibraryModel.db"  # SQLite connection
59
60engine = create_engine(DATABASE_URL, echo=True)
61
62# Create tables in the database
63Base.metadata.create_all(engine)

Creating the Database#

The generated code contains the SQLAlchemy classes that represent the database metadata. If you are using SQLite as DBMS, you can create the database and the tables by running the file as follows:

python sql_alchemy.py

This will create a SQLite database named Librarymodel.db in the same directory where the file is executed. The database looks like this:

../_images/library_db.png

Note

If you want to use another DBMS such as postgresql or mysql, you should change the connection string in the generated code, providing the necessary information to connect to the database: username, password, host, port, and database name.