Trusted answers to developer questions
Trusted Answers to Developer Questions

Related Tags

fastapi
communitycreator

How to use PostgreSQL database in FastAPI

Njoku Ifeanyi Gerald

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
        
schema.py

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 upgrade head

alembic revision --autogenerate -m "New Migration"

Step 8

To kickstart the app, use:

uvicorn main:app --reload

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

RELATED TAGS

fastapi
communitycreator

CONTRIBUTOR

Njoku Ifeanyi Gerald
RELATED COURSES

View all Courses

Keep Exploring