Learn to configure SQLAlchemy with PostgreSQL and query data using raw SQL and ORM in a FastAPI application.
In this tutorial, you’ll learn how to configure SQLAlchemy to create tables in PostgreSQL and how to query data using both raw SQL and SQLAlchemy’s ORM within a FastAPI application. We will cover establishing a database connection, setting up models and dependencies, executing queries, and transitioning from raw SQL to ORM-based queries.─────────────────────────────
Begin by defining your data model and establishing a connection to PostgreSQL using psycopg2. The code snippet below demonstrates the basic setup for the model, connection loop, and sample posts:
Copy
Ask AI
from pydantic import BaseModelimport psycopg2from psycopg2.extras import RealDictCursorimport timeclass Post(BaseModel): title: str content: str published: bool = Truewhile True: try: conn = psycopg2.connect( host='localhost', database='fastapi', user='postgres', password='password123', cursor_factory=RealDictCursor ) cursor = conn.cursor() print("Database connection was successful!") break except Exception as error: print("Connecting to database failed") print("Error:", error) time.sleep(2)my_posts = [ {"title": "title of post 1", "content": "content of post 1", "id": 1}, {"title": "favorite foods", "content": "I like pizza", "id": 2}]
In your main application file, configure the FastAPI app alongside SQLAlchemy by setting up the database URL, engine, session, and dependency injection. Import your models and create all tables using Base.metadata.create_all(bind=engine). See the example below:
Copy
Ask AI
from typing import Optionalfrom fastapi import FastAPI, Response, status, HTTPException, Dependsfrom fastapi.params import Bodyfrom pydantic import BaseModelfrom random import randrangeimport psycopg2from psycopg2.extras import RealDictCursorimport timefrom sqlalchemy.orm import Session, sessionmakerfrom sqlalchemy import create_enginefrom sqlalchemy.ext.declarative import declarative_basefrom . import modelsfrom .database import engine, get_dbmodels.Base.metadata.create_all(bind=engine)app = FastAPI()class Post(BaseModel): title: str content: str published: bool = Truewhile True: try: conn = psycopg2.connect( host='localhost', database='fastapi', user='postgres', password='password123', cursor_factory=RealDictCursor ) cursor = conn.cursor() print("Database connection was successful!") break except Exception as error: print("Connecting to database failed") print("Error:", error) time.sleep(2)my_posts = [ {"title": "title of post 1", "content": "content of post 1", "id": 1}, {"title": "favorite foods", "content": "I like pizza", "id": 2}]
The database dependency function is defined in a separate module as follows:
SQLAlchemy delays executing a query until you explicitly request the results. Consider the following example:
Copy
Ask AI
@app.get("/sqlalchemy")def test_posts(db: Session = Depends(get_db)): query = db.query(models.Post) # This creates the query object. posts = query.all() # The query executes here, fetching all posts. print(posts) return {"data": "successful"}
Before calling .all(), the query object represents the SQL command internally. Invoking .all() triggers the complete SQL command to be generated and executed against your PostgreSQL database.─────────────────────────────
For a more maintainable and testable codebase, you can refactor your endpoints to utilize SQLAlchemy’s ORM. Updating your /posts route to use the dependency-injected session simplifies the operation:
Copy
Ask AI
@app.get("/posts")def get_posts(db: Session = Depends(get_db)): posts = db.query(models.Post).all() # ORM-based query to retrieve all posts. return {"data": posts}
Using the ORM approach reduces manual management of database connections and leverages dependency injection. This not only streamlines testing but also improves code maintainability.
After updating your endpoints, perform the following steps to verify your implementation:
Verify that the PostgreSQL database contains a single post by executing the following SQL command:
Copy
Ask AI
SELECT * FROM public.posts ORDER BY id ASC;
Add a new post using the /posts endpoint. Then, make a new GET request to confirm that multiple posts are retrieved successfully.
The ORM approach encapsulates much of the SQL logic, allowing you to focus on building your FastAPI application while SQLAlchemy handles SQL generation behind the scenes.─────────────────────────────