Relations#
In this page I want to describe the mechanism of sqlalchemy that allows to perform sql JOIN
operation in a really natural for python way. For each “main” table, you can define related essentials and you’ll be able to access them only from queries on the “main” table.
Prepare#
In the following cell we have just defined basic things for sqlalchemy.
!docker run -d --rm\
--name relations_example\
-e POSTGRES_PASSWORD=postgres\
-p 5000:5432\
postgres:15.4 &> /dev/null
!sleep 5
from sqlalchemy import (
create_engine,
Column,
Integer,
String,
ForeignKey
)
from sqlalchemy.orm import (
sessionmaker,
declarative_base,
relationship
)
from random import randint
URL = "postgresql://postgres:postgres@localhost:5000/postgres"
engine = create_engine(URL)
SessionLocal = sessionmaker(
autoflush=False,
autocommit=False,
bind=engine
)
session = SessionLocal()
# defining data model
Base = declarative_base()
Data model#
Data model is a key feature of this page. There are:
MainTable
, which containsSome information that is unique to each record -
id
andtext_var
;Some information that can be mapped to the other
describe
table;
DescribeTable
- auxiliary table that describes certain states of theMainTable
.
So we need a mechanism to tell sqlalcemy
that it needs to join some infromation from DescribeTable
into MainTable
.
With DescribeTable
it’s very simple, you just define primary key and text_var
that simulate some content to be joined.
MainTable
has:
id
as primary key;text_var
that simulate some content;describe_id
in its declaration containsForeignKey
which indicates which field of their third-party table this field is associated with;describe
is a field where objects ofDescribeTable
class will be written to so that they can be accessed.
class DescribeTable(Base):
__tablename__="describe_table"
id = Column(Integer, primary_key=True)
text_var=Column(String)
class MainTable(Base):
__tablename__="main_table"
id = Column(Integer, primary_key=True)
text_var = Column(String)
describe_id = Column(
Integer, ForeignKey("describe_table.id")
)
describe = relationship("DescribeTable")
# duplicate datamodel in the database
Base.metadata.create_all(engine)
Filling of the table#
Below content of the tables is created. Few records that defines mapping for the descriptions. And some random content for the MainTable
.
for i in range(2):
session.add(DescribeTable(
text_var = f"descrion {i+1}"
))
for i in range(10):
session.add(MainTable(
text_var = "".join([chr(randint(97,107)) for i in range(10)]),
describe_id = randint(1,2)
))
session.commit()
%%bash
docker exec -i relations_example psql -U postgres -d postgres
SELECT * FROM describe_table;
SELECT * FROM main_table;
id | text_var
----+------------
1 | descrion 1
2 | descrion 2
(2 rows)
id | text_var | describe_id
----+------------+-------------
1 | kciihbjiii | 1
2 | cgdebdabhh | 1
3 | bichegaghb | 2
4 | kkaidfdiki | 1
5 | icicbkcihj | 1
6 | eijbdfjkff | 1
7 | dhacdkgahd | 2
8 | hhiebijhbc | 2
9 | dccdgfkiee | 2
10 | fhbgideidg | 2
(10 rows)
Query#
An object that describes the entity of the linked table has been declared in the main table, it is through this object that the content of the linked table can be retrieved.
So despite the fact that the query was made in MainTable
the corresponding data from DescribeTable
are automatically pulled into the results.
for main_table_instance in session.query(MainTable).all():
print("============================")
print(
"text_var:", main_table_instance.text_var, "\n"
"describe_id:", main_table_instance.describe_id, "\n"
"description content:", main_table_instance.describe.text_var
)
============================
text_var: kciihbjiii
describe_id: 1
description content: descrion 1
============================
text_var: cgdebdabhh
describe_id: 1
description content: descrion 1
============================
text_var: bichegaghb
describe_id: 2
description content: descrion 2
============================
text_var: kkaidfdiki
describe_id: 1
description content: descrion 1
============================
text_var: icicbkcihj
describe_id: 1
description content: descrion 1
============================
text_var: eijbdfjkff
describe_id: 1
description content: descrion 1
============================
text_var: dhacdkgahd
describe_id: 2
description content: descrion 2
============================
text_var: hhiebijhbc
describe_id: 2
description content: descrion 2
============================
text_var: dccdgfkiee
describe_id: 2
description content: descrion 2
============================
text_var: fhbgideidg
describe_id: 2
description content: descrion 2
Stop container#
!docker stop relations_example
relations_example