LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 2020 min read

Data Access Libraries (SQLAlchemy & Requests)

Learn how Python data science projects pull data in from SQL databases with SQLAlchemy and from REST APIs with requests.

Introduction

Before you can clean, analyze, or model anything, the data has to get into Python in the first place. So far in this course that has mostly meant reading a CSV file. Real projects usually pull data from somewhere live: a production database, or a REST API run by a third party. This lesson covers the two most common libraries for exactly that.

What You Will Learn
  • How SQLAlchemy lets Python talk to SQL databases, both with raw Core queries and with the higher-level ORM.
  • How to pull data out of a database directly into a pandas DataFrame.
  • How requests fetches data from REST APIs and parses JSON responses.

sqlalchemy: Talking to SQL Databases

SQLAlchemy is the standard way Python code talks to relational databases — PostgreSQL, MySQL, SQLite, and others — through one consistent interface. It has two layers you will see referenced constantly: Core, which lets you build and run SQL queries directly, and the ORM (Object-Relational Mapper), which lets you represent database tables as Python classes and rows as Python objects.

pip install sqlalchemy

The Core style is the fastest way to run a query and get data into pandas — it is what you will use most often for pure data science work, since pandas.read_sql() accepts a SQLAlchemy engine directly.

core_style.py
import pandas as pd
from sqlalchemy import create_engine
engine = create_engine("sqlite:///sales.db")
df = pd.read_sql("SELECT * FROM orders WHERE amount > 100", engine)
print(df.head())

The ORM style is more common in application code that reads and writes individual records — for example, a FastAPI backend around a model you trained. It maps a table to a Python class.

orm_style.py
from sqlalchemy import create_engine, Column, Integer, String, Float
from sqlalchemy.orm import declarative_base, Session
engine = create_engine("sqlite:///sales.db")
Base = declarative_base()
class Order(Base):
__tablename__ = "orders"
id = Column(Integer, primary_key=True)
customer = Column(String)
amount = Column(Float)
with Session(engine) as session:
big_orders = session.query(Order).filter(Order.amount > 100).all()
for order in big_orders:
print(order.customer, order.amount)
Output

Click Run to see what this code prints.

Which Style Should You Use?

For pulling data into a DataFrame for analysis, prefer the Core style with pandas.read_sql() — it is shorter and exactly what pandas expects. Reach for the ORM when you are writing an application that creates, updates, and deletes individual records, not just reading bulk data for analysis.

requests: Talking to REST APIs

A huge amount of real-world data lives behind REST APIs rather than in a database you can query directly — weather data, stock prices, public government datasets, internal company services. requests is the standard Python library for making HTTP calls: GET to fetch data, POST to send it, along with headers, authentication, and query parameters.

pip install requests
fetch_api.py
import requests
response = requests.get(
"https://api.example.com/v1/exchange-rates",
params={"base": "USD"},
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
response.raise_for_status() # raises an exception on 4xx/5xx errors
data = response.json()
print(data["rates"]["EUR"])
Output

Click Run to see what this code prints.

It is common to combine requests with pandas to turn an API response straight into a DataFrame for analysis.

api_to_dataframe.py
import pandas as pd
import requests
response = requests.get("https://api.example.com/v1/orders")
response.raise_for_status()
orders = response.json()["results"]
df = pd.DataFrame(orders)
print(df.head())
Always Check the Response

A failed request does not automatically raise an exception in requests — a 404 or 500 response still returns normally. Always call response.raise_for_status(), or explicitly check response.status_code, before trusting response.json().

Common Mistakes

Avoid These Mistakes
  • Building SQL query strings by hand with string concatenation instead of using SQLAlchemy parameter binding — this opens the door to SQL injection.
  • Forgetting response.raise_for_status(), so failed API calls silently return an empty or error payload that gets parsed as if it were real data.
  • Opening a new database connection per query instead of reusing a single engine, which SQLAlchemy pools for you automatically.

Best Practices

  • Use pandas.read_sql() with a SQLAlchemy engine for analysis workloads, and the ORM for application-style read/write code.
  • Store database URLs and API keys in environment variables with python-dotenv, never hardcoded.
  • Always set a timeout on requests calls (requests.get(url, timeout=10)) so a hung server does not freeze your script.
  • Use requests.Session() when making many calls to the same API, to reuse the underlying TCP connection.

Frequently Asked Questions

You still need it under the hood — pandas.read_sql() requires a SQLAlchemy engine (or a raw DBAPI connection) to know how to talk to your specific database.

requests remains the most widely used and most battle-tested HTTP library in Python. httpx is a newer alternative that adds async support and an HTTP/2 client, worth considering if you specifically need asynchronous requests.

Yes — PostgreSQL, MySQL, SQL Server, Oracle, and more, each through a small driver package (like psycopg2 for PostgreSQL) alongside sqlalchemy itself.

Key Takeaways

  • SQLAlchemy Core is the fastest path from a SQL database into a pandas DataFrame.
  • SQLAlchemy ORM maps tables to Python classes for application-style read/write code.
  • requests is the standard way to call REST APIs and parse JSON responses in Python.
  • Always validate API responses with raise_for_status() before trusting the returned data.

Summary

SQLAlchemy and requests cover the two most common ways real data enters a Python project: pulled from a database, or fetched from an API. Next, we look at a third source — scraping data directly out of web pages, using BeautifulSoup and Scrapy.

Lesson 20 Completed
  • You can query a SQL database with SQLAlchemy Core and ORM.
  • You can fetch and parse JSON data from a REST API with requests.
  • You are ready to look at web scraping libraries next.
Next Lesson →

Web Scraping Libraries (BeautifulSoup & Scrapy)