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.
Installation:
pip install pipenv
pipenv shell
pipenv install fastapi fastapi-sqlalchemy pydantic alembic psycopg2 uvicorn python-dotenv
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, Floatfrom sqlalchemy.ext.declarative import declarative_basefrom sqlalchemy.orm import relationshipfrom sqlalchemy.sql import funcBase = 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())
Create another file and name it schema.py
. It is used to write how an object in a model can be easily mapped using ORM
# build a schema using pydanticfrom pydantic import BaseModelclass Book(BaseModel):title: strrating: intauthor_id: intclass Config:orm_mode = Trueclass Author(BaseModel):name:strage:intclass Config:orm_mode = True
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 uvicornfrom fastapi import FastAPIfrom fastapi_sqlalchemy import DBSessionMiddleware, dbfrom schema import Book as SchemaBookfrom schema import Author as SchemaAuthorfrom schema import Bookfrom schema import Authorfrom models import Book as ModelBookfrom models import Author as ModelAuthorimport osfrom dotenv import load_dotenvload_dotenv('.env')app = FastAPI()# to avoid csrftokenErrorapp.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 locallyif __name__ == '__main__':uvicorn.run(app, host='0.0.0.0', port=8000)
.env
..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.
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 fileConfigfrom sqlalchemy import engine_from_configfrom sqlalchemy import poolfrom alembic import context# My codeimport os,sysfrom dotenv import load_dotenvBASE_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 connectionconfig.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.metadatatarget_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 URLand not an Engine, though an Engine is acceptablehere as well. By skipping the Engine creationwe don't even need a DBAPI to be available.Calls to context.execute() here emit the given string to thescript 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 Engineand 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()