Direct PyPika Queries¶
Tortoise exposes a public API for building and executing PyPika queries directly, without creating model instances.
Table Access¶
Use Model.get_table() to get a fresh PyPika Table:
from tortoise.models import Model
from tortoise import fields
class Tournament(Model):
id = fields.IntField(pk=True)
name = fields.TextField()
table = Tournament.get_table()
Query Execution¶
Use execute_pypika to run a PyPika query and get a QueryResult with rows as dicts.
from pypika_tortoise import Query
from tortoise.query_api import execute_pypika
table = Tournament.get_table()
query = Query.from_(table).select(table.id, table.name).where(table.name == "Champions")
result = await execute_pypika(query)
print(result.rows)
print(result.rows_affected)
If your application has multiple database connections configured, you must pass
using_db explicitly:
from tortoise.connection import get_connection
db = get_connection("analytics")
result = await execute_pypika(query, using_db=db)
Rows Affected Semantics¶
QueryResult.rows_affected is always populated, but the meaning depends on backend and
query type:
SQLite: for SELECT, it is the number of rows fetched; for UPDATE/DELETE, it is the delta of total changes.
asyncpg: for SELECT, it is the number of rows fetched; for UPDATE/DELETE, it is parsed from the command status.
MySQL/ODBC/psycopg: typically uses
cursor.rowcount(driver-defined for some statements).
Typed Results¶
You can provide an optional schema to validate or type the results.
Pydantic v2 BaseModel:
from pydantic import BaseModel
class Row(BaseModel):
id: int
name: str
result = await execute_pypika(query, schema=Row)
row = result.rows[0]
print(row.id, row.name)
Pydantic v2 TypeAdapter:
from pydantic import TypeAdapter
adapter = TypeAdapter(dict[str, int | str])
result = await execute_pypika(query, schema=adapter)
TypedDict (typing only, no runtime validation):
from typing import TypedDict
class RowDict(TypedDict):
id: int
name: str
result = await execute_pypika(query, schema=RowDict)
Parameter Binding¶
PyPika will parameterize literal values for you, so avoid formatting SQL by hand:
table = Tournament.get_table()
query = Query.from_(table).select(table.id).where(table.name == "Champions")
result = await execute_pypika(query)
# SQL: SELECT "id" FROM "tournament" WHERE "name"=?
# Params: ["Champions"]