How to use PostgreSQL database in FastAPI

FastAPI is a Python web framework specially for building APIs. In this article, we will be looking into PostgreSQL with Django.

PostgreSQL is an object-relational database that uses and extends the SQL language to scale and store big complicated data in the database.

The example below demonstrates how PostgreSQL can be used alongside FastAPI.

Step 1

Installation:

pip install pipenv
pipenv shell
pipenv install fastapi fastapi-sqlalchemy pydantic alembic psycopg2 uvicorn python-dotenv

Step 2

Create a file and name it models.py. This file is responsible for creating the model for the database.

from sqlalchemy import Column, DateTime, ForeignKey, Integer, String, Float
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
Base = declarative_base()
class Book(Base):
__tablename__ = 'book'
id = Column(Integer, primary_key=True, index=True)
title = Column(String)
rating = Column(Float)
time_created = Column(DateTime(timezone=True), server_default=func.now())
time_updated = Column(DateTime(timezone=True), onupdate=func.now())
author_id = Column(Integer, ForeignKey('author.id'))
author = relationship('Author')
class Author(Base):
__tablename__ = 'author'
id = Column(Integer, primary_key=True)
name = Column(String)
age = Column(Integer)
time_created = Column(DateTime(timezone=True), server_default=func.now())
time_updated = Column(DateTime(timezone=True), onupdate=func.now())

Step 3

Create another file and name it schema.py. It is used to write how an object in a model can be easily mapped using ORMobject-relational mapper.

# build a schema using pydantic
from pydantic import BaseModel
class Book(BaseModel):
title: str
rating: int
author_id: int
class Config:
orm_mode = True
class Author(BaseModel):
name:str
age:int
class Config:
orm_mode = True

Step 4

Create a file and name it main.py. This file is used to create functions or classes that visualize how a route will operate.

import uvicorn
from fastapi import FastAPI
from fastapi_sqlalchemy import DBSessionMiddleware, db
from schema import Book as SchemaBook
from schema import Author as SchemaAuthor
from schema import Book
from schema import Author
from models import Book as ModelBook
from models import Author as ModelAuthor
import os
from dotenv import load_dotenv
load_dotenv('.env')
app = FastAPI()
# to avoid csrftokenError
app.add_middleware(DBSessionMiddleware, db_url=os.environ['DATABASE_URL'])
@app.get("/")
async def root():
return {"message": "hello world"}
@app.post('/book/', response_model=SchemaBook)
async def book(book: SchemaBook):
db_book = ModelBook(title=book.title, rating=book.rating, author_id = book.author_id)
db.session.add(db_book)
db.session.commit()
return db_book
@app.get('/book/')
async def book():
book = db.session.query(ModelBook).all()
return book
@app.post('/author/', response_model=SchemaAuthor)
async def author(author:SchemaAuthor):
db_author = ModelAuthor(name=author.name, age=author.age)
db.session.add(db_author)
db.session.commit()
return db_author
@app.get('/author/')
async def author():
author = db.session.query(ModelAuthor).all()
return author
# To run locally
if __name__ == '__main__':
uvicorn.run(app, host='0.0.0.0', port=8000)

Step 5

  • Create an environment file and name it .env.
  • Inside the .env file, do the following:

DATABASE_URI = 'postgresql://postgres:<password>@localhost/<name_of_the_datbase>'

Here, we will add a link to our PostgreSQL database.

Step 6

After it, run this command:

alembic init alembic

It will create a folder called alembic. Inside the folder, go to the env.py file and do the following:

from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
# My code
import os,sys
from dotenv import load_dotenv
BASE_DIR= os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
load_dotenv(os.path.join(BASE_DIR, '.env'))
sys.path.append(BASE_DIR)
# This is the Alembic Config object, which provides
# Access to the values within the .ini file in use.
config = context.config
# Making a connection
config.set_main_option('sqlalchemy.url', os.environ['DATABASE_URL'])
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
import models
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = models.Base.metadata
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection, target_metadata=target_metadata
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()

Step 7

Run the following code to enable migration.

alembic revision --autogenerate -m "New Migration"

alembic upgrade head

Step 8

To kickstart the app, use:

uvicorn main:app --reload

Then go here, and to use the app go here.

Copyright ©2024 Educative, Inc. All rights reserved