A simple CRUD library built with FastAPI and SQLModel.
Project description
crudcrud
crudcrud is a minimalist, yet powerful, Python library designed to streamline CRUD (Create, Read, Update, Delete) operations in FastAPI applications using SQLModel. It aims for simplicity, excellent developer experience (DX), and a best-in-class onboarding experience. It focuses on getting you up and running quickly, without sacrificing flexibility or control.
Features
- Automatic API Route Generation: Instantly create RESTful API endpoints for your SQLModel models with
SQLModelCRUDRouter. No need to write repetitive boilerplate code for each CRUD operation. - SQLModel Integration: Seamlessly works with SQLModel, combining the power of SQLAlchemy and Pydantic for database models and data validation.
- Engine-Based Initialization: The recommended approach is using the
.from_engine()method, which automatically handles session management, reducing setup complexity. - Customizable: Easily override or extend the default behavior by providing your own session factory or CRUD logic.
- Built-in Error Handling: Handles common database errors gracefully, returning appropriate HTTP status codes and informative error messages. Includes custom exceptions (
CrudException,ItemNotFoundException) for fine-grained error control. - Pagination Support: Built-in support for pagination, allowing you to efficiently handle large datasets.
- Type-Safe: Fully type-hinted for improved code clarity and maintainability.
- Test-Driven: Includes a comprehensive suite of unit tests, ensuring reliability and stability.
- Easy to learn: a single file example is provided.
Installation
pip install crudcrud
Quick Start (Single File Example)
This example demonstrates how to create a complete FastAPI application with CRUD operations for an Item model in a single Python file.
# app.py
from fastapi import FastAPI
from fastapi.responses import RedirectResponse
from sqlmodel import SQLModel, create_engine, Field
from crudcrud import SQLModelCRUDRouter
# --- Database Setup (In-Memory SQLite for Simplicity) ---
engine = create_engine("sqlite:///:memory:", echo=False) # Use in-memory DB for this example
# --- Define your SQLModel ---
class Item(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
name: str
description: str | None = None
# --- Create the Database Tables ---
def create_db_and_tables():
SQLModel.metadata.create_all(engine)
# --- Create the FastAPI App ---
app = FastAPI()
# --- Create the CRUD Router ---
# Use .from_engine() for automatic session handling – the BEST way!
item_router = SQLModelCRUDRouter.from_engine(model=Item, engine=engine, paginate=10)
app.include_router(item_router)
# --- Startup Event: Create Tables ---
@app.on_event("startup")
def on_startup():
create_db_and_tables()
# --- Redirect Root to Docs ---
@app.get("/", include_in_schema=False)
async def root_redirect():
return RedirectResponse(url="/docs")
# --- THAT'S IT! Run the app: ---
# uvicorn app:app --reload
# --- Example Usage (using curl) ---
# Create an item:
# curl -X POST -H "Content-Type: application/json" -d '{"name": "My First Item", "description": "This is awesome!"}' http://localhost:8000/item/
# Get all items:
# curl http://localhost:8000/item/
# Get a specific item (replace 1 with the actual ID):
# curl http://localhost:8000/item/1
# Update an item:
# curl -X PUT -H "Content-Type: application/json" -d '{"name": "Updated Item Name"}' http://localhost:8000/item/1
# Delete an item:
# curl -X DELETE http://localhost:8000/item/1
# Delete all items
# curl -X DELETE http://localhost:8000/item/
This single file demonstrates the core functionality. You can run this directly with uvicorn app:app --reload. It creates an in-memory SQLite database, defines the Item model, creates the CRUD routes, and sets up the FastAPI application. This is the best onboarding experience, as it's fully self-contained and runnable.
Detailed Usage
1. Define Your SQLModel
# models.py
from sqlmodel import SQLModel, Field
class Item(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
name: str
description: str | None = None
2. Create Your FastAPI App and Router
# main.py
from fastapi import FastAPI
from sqlmodel import create_engine
from crudcrud import SQLModelCRUDRouter
from models import Item # Import your model
# Database URL (replace with your actual database URL)
DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(DATABASE_URL, echo=True)
# Create the FastAPI app
app = FastAPI()
# Create the CRUD router using .from_engine() (recommended)
item_router = SQLModelCRUDRouter.from_engine(model=Item, engine=engine, paginate=20)
app.include_router(item_router)
# Optional: Create tables on startup (good for development)
from sqlmodel import SQLModel
@app.on_event("startup")
def on_startup():
SQLModel.metadata.create_all(engine)
3. Run Your Application
uvicorn main:app --reload
Now you have a fully functional API with endpoints for:
- GET
/item/: Get all items (paginated). - GET
/item/{item_id}: Get a specific item by ID. - POST
/item/: Create a new item. - PUT
/item/{item_id}: Update an existing item. - DELETE
/item/{item_id}: Delete an item. - DELETE
/item/: Delete all items.
Advanced Usage: Customizing CRUD Operations
If you need more control over the CRUD operations, you can override the default SQLModelCRUD methods or provide your own get_crud callable to the SQLModelCRUDRouter.
# custom_crud.py
from crudcrud import SQLModelCRUD
from models import Item
from sqlmodel import Session
class CustomItemCRUD(SQLModelCRUD[Item]):
def get_all(self, skip: int = 0, limit: int = 100, session: Session | None = None):
# Implement custom logic for getting all items, e.g., filtering
print("Using custom get_all")
return super().get_all(skip, limit, session)
# main.py (using the custom CRUD class)
from fastapi import FastAPI
from sqlmodel import create_engine
from crudcrud import SQLModelCRUDRouter
from models import Item
from custom_crud import CustomItemCRUD # Import your Custom CRUD
DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(DATABASE_URL, echo=True)
app = FastAPI()
# Pass a custom get_crud callable to from_engine
item_router = SQLModelCRUDRouter.from_engine(
model=Item, engine=engine, get_crud=lambda m: CustomItemCRUD(m, engine=engine)
)
app.include_router(item_router)
from sqlmodel import SQLModel
@app.on_event("startup")
def on_startup():
SQLModel.metadata.create_all(engine)
This example shows how to create a custom CustomItemCRUD class that overrides the get_all method. You can similarly override other methods (get, create, update, delete, delete_all) to implement custom logic. The key is to pass a callable (in this case, a lambda function that instantiates your custom CRUD class) to the get_crud parameter of SQLModelCRUDRouter.from_engine.
Testing
poetry install # Install development dependencies (including pytest)
poetry run pytest
The tests use an in-memory SQLite database, so no external database setup is required. The conftest.py file provides fixtures for the database engine, session, test model, FastAPI application, and test client. The test files (test_crud.py, test_crud_router.py) contain the actual test cases.
License
This project is licensed under the MIT License - see the LICENSE.md file for details.
Contributing
Contributions are welcome! Please feel free to submit pull requests or open issues.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file crudcrud-0.1.1.tar.gz.
File metadata
- Download URL: crudcrud-0.1.1.tar.gz
- Upload date:
- Size: 7.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.5.5 CPython/3.11.10 Linux/6.2.16
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fe331ef0642c6800859e9c1b57bcf954eb4e6e62a0e382b9f91cbf08de16a5fd
|
|
| MD5 |
d6c557b8e59ef01ab176a775abd743ab
|
|
| BLAKE2b-256 |
e4a53372de73d80eb6cec4dc984fedaa71c91b46e6f8fce99318f091248c8565
|
File details
Details for the file crudcrud-0.1.1-py3-none-any.whl.
File metadata
- Download URL: crudcrud-0.1.1-py3-none-any.whl
- Upload date:
- Size: 8.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.5.5 CPython/3.11.10 Linux/6.2.16
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8a2ee422c2d91a426c6d00169f340d538b88a63561f124bfff9bc43a17028993
|
|
| MD5 |
d3a5c2ee1cf736bc49ef933300524b71
|
|
| BLAKE2b-256 |
f2622d22fce98142e0f65c832b68802b49f107b285578606051de38b3bd59be1
|