Neon’s Postgres database is a powerful, serverless option for your Python web applications, and connecting Django and FastAPI to it is straightforward.
Here’s how to connect Django and FastAPI to Neon, demonstrating the process with live code and configuration:
Connecting Django to Neon
First, let’s set up a Django project to use Neon.
1. Install necessary packages:
pip install django psycopg2-binary django-environ
2. Configure your settings.py:
We’ll use django-environ to load database credentials from environment variables, which is a best practice.
# settings.py
import environ
import os
env = environ.Env(
# set casting, default value
DEBUG=(bool, False)
)
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Load .env file if it exists
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))
SECRET_KEY = env('SECRET_KEY')
DEBUG = env('DEBUG')
ALLOWED_HOSTS = env('ALLOWED_HOSTS').split(',')
DATABASES = {
'default': env.db_url(
"DATABASE_URL",
default="postgres://user:password@host:port/dbname"
)
}
# ... other settings
3. Create a .env file:
In the root of your Django project, create a .env file with your Neon connection details. You can find these in your Neon project’s dashboard under the "Connection details" section.
# .env
SECRET_KEY=your-django-secret-key
DEBUG=True
ALLOWED_HOSTS=localhost,127.0.0.1
# Example DATABASE_URL for Neon
# Replace with your actual Neon connection string
DATABASE_URL=postgres://<your_neon_user>:<your_neon_password>@ep-....neon.tech:<port>/<your_neon_dbname>?sslmode=require
4. Configure psycopg2 for SSL:
Neon requires SSL connections. psycopg2-binary handles this automatically when sslmode=require is in the connection string.
5. Run migrations:
python manage.py makemigrations
python manage.py migrate
This will connect to your Neon database and set up your initial tables.
Connecting FastAPI to Neon
Now, let’s connect a FastAPI application to Neon.
1. Install necessary packages:
pip install fastapi uvicorn asyncpg sqlalchemy databases[postgresql]
We use asyncpg for asynchronous database operations and SQLAlchemy for ORM capabilities, with databases acting as a convenient interface.
2. Create your FastAPI app and database connection:
# main.py
from fastapi import FastAPI
from sqlalchemy import create_engine
from databases import Database
import os
# Load database URL from environment variable
DATABASE_URL = os.environ.get("DATABASE_URL", "postgres://user:password@host:port/dbname?sslmode=require")
# Use asyncpg driver for asynchronous operations
database = Database(DATABASE_URL)
# SQLAlchemy engine for ORM and sync operations if needed
# Note: For pure async, you might not need this engine explicitly for basic queries.
# However, it's useful for migrations or when integrating with ORMs like SQLAlchemy ORM.
engine = create_engine(DATABASE_URL)
app = FastAPI()
@app.on_event("startup")
async def startup_event():
await database.connect()
print("Database connected.")
@app.on_event("shutdown")
async def shutdown_event():
await database.disconnect()
print("Database disconnected.")
@app.get("/")
async def read_root():
# Example query: fetch the version of PostgreSQL
query = "SELECT version()"
result = await database.fetch_one(query)
return {"message": "Connected to Neon!", "db_version": result["version"]}
# Example of creating a simple table and inserting data (for demonstration)
from sqlalchemy import Table, Column, Integer, String, MetaData
metadata = MetaData()
items = Table(
"items",
metadata,
Column("id", Integer, primary_key=True),
Column("name", String),
Column("description", String),
)
@app.on_event("startup")
async def create_tables():
# This is a simple way to create tables. For production, use migration tools like Alembic.
metadata.create_all(engine)
print("Tables created (if they didn't exist).")
@app.post("/items/")
async def create_item(name: str, description: str):
query = items.insert().values(name=name, description=description)
await database.execute(query)
return {"name": name, "description": description}
@app.get("/items/")
async def read_items():
query = items.select()
return await database.fetch_all(query)
3. Set your .env file:
Similar to Django, create a .env file in your FastAPI project’s root:
# .env
DATABASE_URL=postgres://<your_neon_user>:<your_neon_password>@ep-....neon.tech:<port>/<your_neon_dbname>?sslmode=require
4. Run your FastAPI application:
uvicorn main:app --reload
You can then access http://localhost:8000/ to see the "Connected to Neon!" message and the database version. You can also test the /items/ endpoints.
The Mental Model: How it Works
The core of connecting to Neon, or any Postgres database, lies in the connection string and the database driver.
- Connection String: This is a URL that encapsulates all the information your application needs to find and authenticate with your database:
postgres://user:password@host:port/dbname. Thesslmode=requireparameter is crucial for Neon, ensuring a secure connection. - Database Driver: This is the library that translates your application’s database requests into the Postgres protocol. For Python, popular choices include
psycopg2(synchronous) andasyncpg(asynchronous). These libraries handle the low-level communication, including SSL negotiation. - Libraries/Frameworks: Django and FastAPI integrate these drivers. Django uses
psycopg2by default for its ORM. FastAPI, being asynchronous, benefits greatly fromasyncpg. Libraries likedatabasesprovide a higher-level, often asynchronous, interface that can work with different drivers.
The key is ensuring your application is configured with the correct connection string and that the chosen driver is installed and correctly configured (especially for SSL).
The One Thing Most People Don’t Know
When using Neon’s serverless architecture, especially with asynchronous frameworks like FastAPI, you might encounter connection pool exhaustion or slow response times if you’re not mindful of connection management. Neon’s autoscaling is excellent, but each connection has overhead. Instead of opening a new connection for every single request in a highly concurrent application, use a connection pool. Libraries like SQLAlchemy (when used with asyncpg for async applications) or dedicated pooling libraries can manage a set of open connections, reusing them for subsequent requests. This significantly reduces latency and prevents hitting Neon’s limits on concurrent connections, especially during traffic spikes. For databases, you can configure pooling:
# Example with databases and pooling
from databases import Database
import os
DATABASE_URL = os.environ.get("DATABASE_URL", "postgres://...")
# Configure pooling with max_connections
database = Database(DATABASE_URL, min_size=1, max_size=20) # Adjust max_size as needed
This allows your application to handle more requests efficiently by maintaining a pool of active connections.
The next step is often to implement more complex data modeling and querying, potentially integrating an ORM like SQLAlchemy ORM with your FastAPI application for more structured database interactions.