Skip to content

Instantly share code, notes, and snippets.

@juftin
Last active August 19, 2023 19:56
Show Gist options
  • Save juftin/91dee06998771f13788880d387d7022d to your computer and use it in GitHub Desktop.
Save juftin/91dee06998771f13788880d387d7022d to your computer and use it in GitHub Desktop.
FastAPI Users + SQLModel
"""
FastAPI Users + SQLModel
"""

FastAPI Users + SQLModel

You will notice that the SQLModel example is very similar to the SQLAlchemy example for fastapi-users. This is because SQLModel is built on top of SQLAlchemy and pydantic.

There are a few important differences you should take note of:

app/db.py

  • Removing the DeclarativeBase SQLAlchemy base class.
  • Using fastapi_users.db.SQLModelBaseUserDB instead of fastapi_users.db.SQLAlchemyBaseUserTable.
  • Using fastapi_users.db.SQLModelUserDatabaseAsync instead of fastapi_users.db.SQLAlchemyUserDatabase.
  • Setting the class_ parameter of sessionmaker to AsyncSession.
  • Using SQLModel.metadata.create_all instead of Base.metadata.create_all.

app/users.py

  • Using fastapi_users.db.SQLModelUserDatabaseAsync instead of fastapi_users.db.SQLAlchemyUserDatabase.
from fastapi import Depends, FastAPI
from app.db import User, create_db_and_tables
from app.docstrings import app_description
from app.schemas import UserCreate, UserRead, UserUpdate
from app.users import auth_backend, current_active_user, fastapi_users
app = FastAPI()
app.include_router(
fastapi_users.get_auth_router(auth_backend), prefix="/auth/jwt", tags=["auth"]
)
app.include_router(
fastapi_users.get_register_router(UserRead, UserCreate),
prefix="/auth",
tags=["auth"],
)
app.include_router(
fastapi_users.get_reset_password_router(),
prefix="/auth",
tags=["auth"],
)
app.include_router(
fastapi_users.get_verify_router(UserRead),
prefix="/auth",
tags=["auth"],
)
app.include_router(
fastapi_users.get_users_router(UserRead, UserUpdate),
prefix="/users",
tags=["users"],
)
@app.get("/authenticated-route")
async def authenticated_route(user: User = Depends(current_active_user)):
return {"message": f"Hello {user.email}!"}
@app.on_event("startup")
async def on_startup():
# Not needed if you setup a migration system like Alembic
await create_db_and_tables()
from typing import AsyncGenerator
from fastapi import Depends
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.orm import sessionmaker
from sqlmodel import SQLModel
from sqlmodel.ext.asyncio.session import AsyncSession
from fastapi_users_db_sqlmodel import SQLModelBaseUserDB, SQLModelUserDatabaseAsync
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
class User(SQLModelBaseUserDB, table=True):
pass
engine = create_async_engine(DATABASE_URL, future=True)
async_session_maker = sessionmaker(
engine,
class_=AsyncSession,
expire_on_commit=False,
)
async def create_db_and_tables():
async with engine.begin() as conn:
await conn.run_sync(SQLModel.metadata.create_all)
async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
async with async_session_maker() as session:
yield session
async def get_user_db(session: AsyncSession = Depends(get_async_session)):
yield SQLModelUserDatabaseAsync(session, User)
fastapi
fastapi-users
fastapi-users-db-sqlmodel
sqlmodel
uvicorn[standard]
aiosqlite
import uuid
from fastapi_users import schemas
class UserRead(schemas.BaseUser[uuid.UUID]):
pass
class UserCreate(schemas.BaseUserCreate):
pass
class UserUpdate(schemas.BaseUserUpdate):
pass
import uuid
from typing import Optional
from app.db import User, get_user_db
from fastapi import Depends, Request
from fastapi_users import BaseUserManager, FastAPIUsers, UUIDIDMixin
from fastapi_users.authentication import (
AuthenticationBackend,
BearerTransport,
JWTStrategy,
)
from fastapi_users_db_sqlmodel import SQLModelUserDatabaseAsync
SECRET = "SECRET"
class UserManager(UUIDIDMixin, BaseUserManager[User, uuid.UUID]):
reset_password_token_secret = SECRET
verification_token_secret = SECRET
async def on_after_register(self, user: User, request: Optional[Request] = None):
print(f"User {user.id} has registered.")
async def on_after_forgot_password(
self, user: User, token: str, request: Optional[Request] = None
):
print(f"User {user.id} has forgot their password. Reset token: {token}")
async def on_after_request_verify(
self, user: User, token: str, request: Optional[Request] = None
):
print(f"Verification requested for user {user.id}. Verification token: {token}")
async def get_user_manager(user_db: SQLModelUserDatabaseAsync = Depends(get_user_db)):
yield UserManager(user_db)
bearer_transport = BearerTransport(tokenUrl="auth/jwt/login")
def get_jwt_strategy() -> JWTStrategy:
return JWTStrategy(secret=SECRET, lifetime_seconds=3600)
auth_backend = AuthenticationBackend(
name="jwt",
transport=bearer_transport,
get_strategy=get_jwt_strategy,
)
fastapi_users = FastAPIUsers[User, uuid.UUID](get_user_manager, [auth_backend])
current_active_user = fastapi_users.current_user(active=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment