FastAPI Tortoise ORM


What is Tortoise ORM?

Tortoise ORM is an easy-to-use, lightweight, and fully-featured Object-Relational Mapping (ORM) library for Python, built with asynchronous support. Tortoise ORM is designed to work with async frameworks like FastAPI and provides a simple interface for interacting with databases using Python objects. It supports multiple databases, including PostgreSQL, MySQL, and SQLite, and enables you to interact with databases without writing raw SQL.


How do you install Tortoise ORM in FastAPI?

To use Tortoise ORM with FastAPI, you need to install Tortoise ORM and its required dependencies using pip. You can also install the database driver for the specific database you are using, such as aiosqlite for SQLite, asyncpg for PostgreSQL, or aiomysql for MySQL.

Example of installing Tortoise ORM with SQLite support:

pip install tortoise-orm aiosqlite

For PostgreSQL, you can use:

pip install tortoise-orm asyncpg

How do you configure Tortoise ORM with FastAPI?

To configure Tortoise ORM with FastAPI, you need to initialize the Tortoise ORM and define the database models. You also need to connect the ORM to the database in your FastAPI app's startup and shutdown events.

Example of configuring Tortoise ORM with FastAPI:

from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise

app = FastAPI()

register_tortoise(
    app,
    db_url="sqlite://db.sqlite3",
    modules={"models": ["app.models"]},
    generate_schemas=True,
    add_exception_handlers=True
)

In this example, Tortoise ORM is initialized with an SQLite database. The register_tortoise function connects the ORM to FastAPI, automatically generates database schemas, and adds exception handling.


How do you define Tortoise ORM models in FastAPI?

Tortoise ORM models are Python classes that define the structure of your database tables. These classes inherit from tortoise.models.Model, and each attribute of the class represents a column in the table. You also define the data type for each field using Tortoise ORM's field types.

Example of defining a Tortoise ORM model:

from tortoise.models import Model
from tortoise import fields

class User(Model):
    id = fields.IntField(pk=True)
    username = fields.CharField(max_length=100)
    email = fields.CharField(max_length=255, unique=True)

In this example, the User model represents a table with three fields: id (primary key), username (a character field), and email (a unique character field).


How do you perform CRUD operations using Tortoise ORM in FastAPI?

With Tortoise ORM, you can perform CRUD (Create, Read, Update, Delete) operations using the built-in methods provided by the ORM. You can create, query, update, and delete records from the database using asynchronous functions.

Example of performing CRUD operations:

from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise
from tortoise.models import Model
from tortoise import fields

app = FastAPI()

class User(Model):
    id = fields.IntField(pk=True)
    username = fields.CharField(max_length=100)
    email = fields.CharField(max_length=255, unique=True)

register_tortoise(
    app,
    db_url="sqlite://db.sqlite3",
    modules={"models": ["__main__"]},
    generate_schemas=True,
    add_exception_handlers=True
)

@app.post("/users/")
async def create_user(username: str, email: str):
    user = await User.create(username=username, email=email)
    return user

@app.get("/users/")
async def read_users():
    users = await User.all()
    return users

@app.put("/users/{user_id}")
async def update_user(user_id: int, username: str, email: str):
    user = await User.filter(id=user_id).update(username=username, email=email)
    return {"message": "User updated"}

@app.delete("/users/{user_id}")
async def delete_user(user_id: int):
    await User.filter(id=user_id).delete()
    return {"message": "User deleted"}

In this example, the application defines routes to create, read, update, and delete users using Tortoise ORM's asynchronous methods. The create() method adds new records, all() retrieves all records, update() modifies records, and delete() removes records from the database.


How do you handle relationships in Tortoise ORM models?

Tortoise ORM supports relationships between models, including one-to-many, many-to-one, and many-to-many relationships. You define relationships using fields such as ForeignKeyField for many-to-one relationships and ManyToManyField for many-to-many relationships.

Example of defining relationships in Tortoise ORM:

class Post(Model):
    id = fields.IntField(pk=True)
    title = fields.CharField(max_length=255)
    content = fields.TextField()
    author = fields.ForeignKeyField("models.User", related_name="posts")

class User(Model):
    id = fields.IntField(pk=True)
    username = fields.CharField(max_length=100)
    email = fields.CharField(max_length=255, unique=True)
    posts = fields.ReverseRelation["Post"]

In this example, the Post model has a foreign key to the User model, indicating a one-to-many relationship. The posts field in the User model is a reverse relation, allowing you to access all posts created by the user.


How do you perform database migrations with Tortoise ORM?

Tortoise ORM supports database migrations using a tool called aerich. Aerich tracks changes to your models and applies them to the database, making it easy to manage database schema changes.

Example of setting up Aerich for database migrations:

pip install aerich
aerich init -t app.models.TORTOISE_ORM
aerich init-db

After initializing Aerich, you can generate and apply migrations whenever your models change.


How do you serialize Tortoise ORM models for API responses?

Tortoise ORM provides the to_dict() and values() methods to serialize models into dictionaries, which can be returned in API responses. These methods make it easy to convert model instances into JSON-friendly data.

Example of serializing models for responses:

@app.get("/users/")
async def read_users():
    users = await User.all().values("id", "username", "email")
    return users

In this example, the values() method is used to return a list of users, where each user is represented as a dictionary containing specific fields (id, username, and email).


How do you use Pydantic models with Tortoise ORM in FastAPI?

FastAPI uses Pydantic models to validate and serialize request and response data. You can integrate Tortoise ORM with Pydantic models using Tortoise's pydantic_model_creator() function, which generates Pydantic models based on your Tortoise ORM models.

Example of integrating Pydantic with Tortoise ORM:

from tortoise.contrib.pydantic import pydantic_model_creator

User_Pydantic = pydantic_model_creator(User, name="User")

@app.get("/users/", response_model=List[User_Pydantic])
async def read_users():
    users = await User.all()
    return await User_Pydantic.from_queryset(users)

In this example, the pydantic_model_creator() function creates a Pydantic model based on the User model. This Pydantic model is then used in the response, and FastAPI automatically validates and serializes the response data.

Ads