- Lab
- Core Tech

Guided: Working with a Relational Database in Python
In this lab, you'll build a Python application that connects to a relational database using the SQLAlchemy ORM to fetch and manage data. You'll be responsible for setting up a connection with the ORM, retrieving data, and establishing relationships across multiple tables. By the end of this lab, you should have gained practical experience with using relational databases in Python.

Path Info
Table of Contents
-
Challenge
Introduction
Overview
Relational databases are used to store and organize structured data using tables with defined relationships. In this lab, you will be working with relational databases is through SQLAlchemy, an ORM (Object-Relational Mapper) that allows developers to interact with databases using Python classes and objects instead of raw SQL. Although this is far from being the only way to interact with relational databases, SQLAlchemy is currently the most commonly used ORM for relational databases(DBs) through python.
Application Scenario
The premise of this lab is that you are trying to estimate ad revenue generated by your site whenever a user visits the site with a specific ad being displayed. If the user clicks the ad, the ad revenue generated gets multiplied by a specific amount. However, the percentage of users who actually click an ad typically varies depending on the advertiser. The formula that is used to estimate your ad revenue is a weighted sum that factors in the base rate paid per visitor, estimated click rate, and the multiplier per click.
Your site has multiple advertisers that display content on it and each of them has their own values for base rates, click rates, and click multipliers that are stored in a SQLite database. You will need to work with this database using the SQLAlchemy ORM to query data and use it to calculate your ad revenue.
Goals of the Application
The first thing to note is that SQLAlchemy is installed as a dependency in the Python virtual environment. To activate the virtual environment during this lab, use the command
source .venv/bin/activate
. You can check that the virtual environment is activated withwhich python
, which should print a filepath pointing to apython
exe within the.venv
directory. You will also seeworkspace
prefixed with.venv
. To deactive this virtual environment, simply enter the commanddeactivate
.The main goals you will need to accomplish with this lab are:
- Establishing a connection with the database(db)
- Define models for interacting with the database using the SQLAlchemy ORM
- Create a relationship between tables with SQLAlchemy and using that data to estimate ad revenue.
To accomplish these goals, you will be working in the
db/advertiser_model.py
,db/database.py
,revenue.py
andseed_data.py
files.There is also a
solution
directory for you to check your implementations at any time. In addition, if you ever need to re-seed your database for whatever reason, use the commandpython seed_data.py
. -
Challenge
Defining Models and Connecting to the DB
Implementing the Base Class Factory and DB Models
Open the
db/advertiser_model.py
file. Inside this file, you will find all the relevant imports from thesqlalchemy
library needed for this file as well as theAdCampaign
class, which will represent theAdCampaign
model to be stored in the database. For the purpose of this lab, anAdCampaign
is simply a tag that will be attached to an advertiser. As an example, anAdCampaign
could be something like a "summer sale" or a "holiday sale" that an advertiser might promote to entice more visitors.Now take a look at the structure of
AdCampaign
, as custom base classes you define for SQLAlchemy will typically follow this format. Each class starts with a__tablename__
representing the name of the table, while the following properties are values that each entry of anAdCampaign
can have.Each property is a
Mapped
type that is then mapped to a column using the ORMsmapped_column
. In other words,mapped_column
allows you to map a property with a certain value to a column within the database.Your objective here is to define a new model class called
Advertiser
similar to howAdCampaign
is defined, but before you do so you will need to create theBase
class factory.
A
Base
class factory takes the metadata from each of your custom base classes which the ORM can then use to generate the tables and entries for your models. To do so, you will first need to define aBase
class and then pass it into your custom model classes.Instructions
1. Create a `class` called `Base()`. Pass in the `DeclarativeBase` that is imported from SQLAlchemy. 2. Inside this base class, just leave a `pass` statement. 3. Modify `AdCampaign`s class signature to be `class AdCampaign(Base)`. 4. Modify `Advertiser`s class signature to be `class Advertiser(Base)`.
Now that the
Base
class factory is setup, you will need to implement theAdvertiser
model.Instructions
1. Create a `__tablename__` and pass it the name `advertisers` 2. Define an `id` and `name` property just like they are defined in `AdCampaign` 3. Define `base_revenue`, `click_rate`, and `click_multiplier` properties. These properties should be mapped to a `float` type and you need to pass in `Float, Nullable=False` as parameters to `mapped_column()`.
Setting up the DB Connection
Now that the models have been defined, you will need to setup the connection to the DB within
db/database.py
.The very first thing you should do here is import the
Base
class factory you made withfrom .advertiser_model import Base
. Now to setup the DB connection, you will need to create an engine with a path to your database file. Then you will need to create aSession
factory usingsessionmaker
. In SQLAlchemy, these sessions are required whenever you want to make transactions to the database. Actions made in a session are not pushed through to the database until you callsession.commit()
, similar to how Git operates.
Everything you need to setup this connection has already been imported (aside from
Base
which you should have imported by now).Instructions
1. Create a `DATABASE_URL` variable and set it to `"sqlite:///./db/ad_revenue.db"`. 2. Create an `engine` variable and set it to `create_engine()`, passing in the `DATABASE_URL`. 3. Create a `SessionLocal` variable and set it to `sessionmaker()`, passing in the parameters `bind=engine, autoflush=False` to `sessionmaker()`. 4. Replace the `pass` placeholder in `init_db()` with `Base.metadata.create_all(bind=engine)` 5. Replace the `pass` placeholder in `get_session()` with `return SessionLocal()`.
After completing these steps, you have setup an engine that binds all sessions to the database filepath that you specified. Whenever you wish to perform transactions with your database, the
SessionLocal
instance will be invoked to create a session(usingget_session()
). Theinit_db()
function will be utilized to initially populate all the tables mapped to your models using theBase
class factory. This function will be used inseed_data.py
. -
Challenge
Seeding the DB and Displaying Ad Revenue
Seeding Data
Now take a look at
seed_data.py
. This file will be used to seed your database with some initial data that will then be used to calculate estimated ad revenue per visitor. If a database file has not been created for whatever reason, such as a clean slate or running it for the first time, running this file will automatically create the db file asad_revenue.db
within thedb
directory. Go ahead and completeseed_data.py
.Instructions
1. At the start of `seed_advertisers()`, call `init_db()` which you implemented in `database.py`. This will initialize the tables in the db file. 2. Go to the nested `for` loop in the `with` statement. Right after the `campaign_names`, which you won't need to worry about for now, right a query `stmt` with `select(Advertiser).where(Advertiser.name == data["name"])`. This is another usage of an ORM like SQLAlchemy, as you don't have to worry about formatting raw SQL statements in code. 3. After the `stmt`, define an `advertiser` variable and set it to `session.scalars(stmt).first()`. The `scalars()` method executes the `stmt` being passed in and `first()` retrieves the first matching item. 4. After the `advertiser`, write a conditional `if` statement that checks if `advertiser` is null. If it is, set it `Advertiser(**data)` and create a transaction to add it to the db with `session.add(advertiser)`. 5. Right before the print statement, add `session.commit()`.
By completing these instructions, you have written a query that searches the database for any advertisers whose name matches the ones being seeded in the
advertisers
collection. If it does not already exist, you create a mappedAdvertiser
instance using the object data and stage it to be added to the database. After the transactions are staged, you commit them to the database just like you would commit changes with Git operations.
Calculating Ad Revenue
Now it's time to head to
revenue.py
to calculate ad revenue per visitor for each advertiser. The revenue calculation and library imports are all done for you, so all you need to do is write a query to retrieve advertiser data from the database to fill into the formula.Instructions
1. Right before the `for` loop in the `with` statement, define a `stmt` query with `select(Advertiser)`. 2. Define an `advertisers` variable set to `advertisers = session.scalars(stmt).all()`. This time you are keeping all the retrieved `Advertiser` dataOnce this is done, you can execute
python seed_data.py
if you haven't already to generate the db file and populate it with some seeded advertisers. Then dopython revenue.py
to display each advertiser and their expected revenue per visitor. You should see something like the followingSpoiler
Advertiser: PS-Alpha Expected Revenue per Visitor = $0.11Advertiser: PS-Tech Expected Revenue per Visitor = $0.09
Advertiser: PS-Market Expected Revenue per Visitor = $0.12
Advertiser: PS-Fit Expected Revenue per Visitor = $0.05
Advertiser: PS-Industrial Expected Revenue per Visitor = $0.18
Advertiser: PS-Stellar Expected Revenue per Visitor = $0.26
Next Up
There is one last thing you need to do which is to setup a relationship between the
Advertiser
you implemented and someAdCampaign
s, which you will tackle in the next step. -
Challenge
Relations
Creating Relationships between Tables
Being able to make connections between tables of data is the hallmark of a relational database. For this lab, you will need to create a one-to-many relationship between
Advertiser
s andAdCampaign
s. The SQLAlchemy ORM typically accomplishes this through therelationship()
function, which you will need use back indb/advertiser_model.py
. You will also be modifyingseed_data.py
andrevenue.py
to link and displayAdCampaign
s to their respectiveAdvertiser
s.Instructions
1. Head to `advertiser_model.py` and head to the `AdCampaign` class. After `name` define a `advertiser_id` property that is mapped to an `int`. Pass in `ForeignKey('advertisers.id')` to its `mapped_column()` which will refer it to the id of the advertiser it is related to. 2. Create another property called `advertiser` that is mapped to `"Advertiser"` set to `relationship("Advertiser", back_populates="campaigns")`. 3. In the `Advertiser` class, add a new property called `campaigns` that is mapped to `List["AdCampaign"]`. Set it to `relationship(back_populates="advertiser")
Doing this sets up a bidirectional relationship between
Advertiser
andAdCampaign
, which you will take advantage of to reseed your database inseed_data.py
Instructions
1. In `seed_data.py`, replace the `if` statement with and `else`. Inside this `else` block, add the line `advertiser.campaigns = [AdCampaign(name=name) for name in campaign_names]` between the `session.add()` statement and `advertiser` assignment. 2. Uncomment the code snippet containing the `if` statement regarding campaigns.In the previous step you defined a relationship between
Advertiser
andAdCampaign
. Now you've modifiedseed_data.py
so that some of the seeded advertisers are now linked with certain ad campaigns. You can runpython seed_data.py
again to update your db with the new seeding or delete the file and run the command if you want a clean slate. Both should be fine.
Lastly, you will need to update
revenue.py
to display campaigns linked to an advertiser.Instructions
1. Head to `revenue.py`. Change the `stmt` to be `select(Advertiser).options(selectinload(Advertiser.campaigns))` 2. Uncomment the code snippet containing the `if` statement regarding campaigns.Using
selectinload
this time performs eager loading of records, which is both performant and intentional in this context since you want to grab all the campaigns related to an advertiser. Once you've done this, performingpython revenue.py
should now display the appropriateAdCampaign
s that are related to their advertiser. Keep in mind that not everyAdvertiser
has anAdCampaign
.
Conclusion
Congratulations on completing this lab! To reiterate what's been covered, you have down the following:
- Setup a connection with your DB through the SQLAlchemy ORM
- Defined custom model classes, created tables, and made sessions for transactions through the
Base
andsessionmaker
factories - Written queries to interact/retrieve data from the DB
- Established relationships across different tables
- Used this relational data to calculate and display ad revenue
What's a lab?
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Provided environment for hands-on practice
We will provide the credentials and environment necessary for you to practice right within your browser.
Guided walkthrough
Follow along with the author’s guided walkthrough and build something new in your provided environment!
Did you know?
On average, you retain 75% more of your learning if you get time for practice.