API Cheatsheet
Complete API reference.
| Method |
Example |
Returns |
Notes |
| Instance Methods |
save() |
await user.save() |
Self |
update_fields for partial |
delete() |
await user.delete() |
int |
Delete instance |
refresh() |
await user.refresh() |
Self |
Reload from DB |
pre_save() |
override |
— |
Hook; is_create, update_fields |
post_save() |
override |
— |
Hook; is_create, update_fields |
pre_delete() |
override |
— |
Hook before delete |
post_delete() |
override |
— |
Hook after delete |
| Manager Methods |
create() |
User.objects.create(name="John") |
Model |
Insert + return |
bulk_create() |
User.objects.bulk_create([...]) |
list[Model] |
Bulk INSERT |
bulk_update() |
User.objects.bulk_update([...], ["age"]) |
int |
Bulk UPDATE |
get() |
User.objects.get(id=42) |
Model |
Raises if 0 or >1 |
get_or_none() |
User.objects.get_or_none(id=42) |
Model | None |
None if not found |
get_or_create() |
User.objects.get_or_create(email="...") |
(Model, bool) |
Atomic |
count() |
User.objects.count() |
int |
Count all |
| Query Builder |
filter() |
.filter(is_active=True, age__gte=18) |
Query |
WHERE conditions |
exclude() |
.exclude(status="banned") |
Query |
WHERE NOT |
order_by() |
.order_by("-created_at") |
Query |
ORDER BY |
limit() |
.limit(10) |
Query |
LIMIT |
offset() |
.offset(20) |
Query |
OFFSET |
prefetch() |
.prefetch("posts") |
Query |
Load reverse FK/M2M |
join() |
.join("author") |
Query |
FK JOIN |
distinct() |
.distinct() |
Query |
DISTINCT |
group_by() |
.group_by("status") |
Query |
GROUP BY |
having() |
.having(count__gte=5) |
Query |
HAVING |
annotate() |
.annotate(n=Count("posts")) |
Query |
Computed fields |
union() |
.union(other_qs) |
Query |
UNION |
for_update() |
.for_update() |
Query |
Row lock |
| Terminal Methods |
all() |
await qs.all() |
list[Model] |
Execute SELECT |
first() |
await qs.first() |
Model | None |
First row |
last() |
await qs.last() |
Model | None |
Last row |
count() |
await qs.count() |
int |
COUNT(*) |
exists() |
await qs.exists() |
bool |
EXISTS check |
delete() |
await qs.delete() |
int |
Bulk DELETE |
update() |
await qs.update(status="x") |
int |
Bulk UPDATE |
increment() |
await qs.increment("views", by=1) |
int |
Atomic increment |
sum() |
await qs.sum("views") |
number |
SUM |
avg() |
await qs.avg("age") |
float |
AVG |
max() |
await qs.max("price") |
Any |
MAX |
min() |
await qs.min("price") |
Any |
MIN |
values() |
await qs.values("id", "name") |
list[dict] |
Dict projection |
values_list() |
await qs.values_list("id", flat=True) |
list |
Tuple projection |
| Debug & Introspection |
sql() |
qs.sql() |
(str, list) |
SQL + params |
query() |
qs.query() |
dict |
Query IR |
explain() |
await qs.explain(analyze=True) |
str |
Query plan |
| Expressions |
Q |
Q(age__gte=18) & Q(status="active") |
— |
AND/OR/NOT |
F |
F("views") + 1 |
— |
Field reference |
Count |
Count("posts") |
— |
Aggregate |
Sum/Avg/Max/Min |
Sum("amount") |
— |
Aggregates |
Concat |
Concat("first", "last") |
— |
String concat |
Coalesce |
Coalesce("nick", "name") |
— |
First non-NULL |
RawSQL |
RawSQL("LOWER(name)") |
— |
Raw SQL |
| Transactions |
atomic() |
async with atomic(): ... |
— |
Nested savepoints |
Examples
Basic Operations
# Simple query
users = await User.objects.filter(is_active=True, age__gte=18).all()
# With prefetch and ordering
users = await User.objects \
.prefetch("posts") \
.filter(is_active=True) \
.order_by("-created_at") \
.limit(10) \
.all()
# Join for FK
posts = await Post.objects.join("author").filter(status="draft").all()
# Get single object
user = await User.objects.get(id=42)
user = await User.objects.get_or_none(email="test@test.com")
Complex Conditions
# Q expressions
users = await User.objects.filter(
Q(age__gte=18) & (Q(status="active") | Q(status="premium"))
).all()
# Exclusion
users = await User.objects.exclude(status="banned").all()
Create
# Simple create
user = await User.objects.create(name="John", age=25)
# Get or create
user, created = await User.objects.get_or_create(
email="test@test.com",
defaults={"name": "John", "age": 25}
)
# Bulk create
users = await User.objects.bulk_create([
User(name="John", age=25),
User(name="Jane", age=30),
])
Update
# Instance update (full UPDATE)
user.age = 26
await user.save()
# Partial update via Query
count = await User.objects.filter(is_active=False).update(status="archived")
# Atomic update with F()
count = await User.objects.filter(id=42).update(views=F("views") + 1)
# Atomic increment
count = await Post.objects.filter(id=42).increment("views", by=1)
# Bulk update
count = await User.objects.bulk_update(
[user1, user2, user3],
fields=["status", "updated_at"]
)
Delete
# Instance delete
await user.delete()
# Bulk delete via Query
count = await User.objects.filter(is_active=False).delete()
Aggregation
# Annotate - add computed fields
users = await User.objects \
.annotate(posts_count=Count("posts")) \
.filter(posts_count__gt=5) \
.all()
# Group by + having
stats = await Post.objects \
.group_by("status") \
.annotate(count=Count("id"), avg_views=Avg("views")) \
.having(count__gte=10) \
.all()
# Terminal aggregates
total_views = await Post.objects.filter(status="published").sum("views")
avg_age = await User.objects.filter(is_active=True).avg("age")
max_price = await Product.objects.max("price")
Count & Exists
# Count with filters
count = await User.objects.filter(is_active=True).count()
# Count all
count = await User.objects.count()
# Exists (faster than count for existence check)
has_active = await User.objects.filter(is_active=True).exists()
Values & Values List
# Dictionaries instead of models
users_data = await User.objects.filter(is_active=True).values("id", "name", "email")
# [{"id": 1, "name": "John", "email": "..."}, ...]
# Flat list
user_ids = await User.objects.filter(is_active=True).values_list("id", flat=True)
# [1, 2, 3, 4, ...]
# Tuples
user_pairs = await User.objects.values_list("id", "name")
# [(1, "John"), (2, "Jane"), ...]
Advanced Queries
# Union
active = User.objects.filter(status="active")
premium = User.objects.filter(status="premium")
combined = await active.union(premium).all()
# Distinct
unique_statuses = await Post.objects.distinct().values_list("status", flat=True)
# First / Last
newest = await Post.objects.order_by("-created_at").first()
oldest = await Post.objects.order_by("created_at").first()
Transactions
from oxyde.db import transaction
# Django-style atomic transactions
async with transaction.atomic():
user = await User.objects.create(name="John")
await Post.objects.create(author_id=user.id, title="First post")
# Rollback on exception
# Nested transactions (savepoints)
async with transaction.atomic():
user = await User.objects.create(name="John")
async with transaction.atomic(): # Creates savepoint
await Post.objects.create(author_id=user.id, title="First post")
Introspection
# Get SQL query
qs = User.objects.filter(age__gte=18).order_by("-created_at")
sql, params = qs.sql()
print(f"SQL: {sql}")
print(f"Params: {params}")
# Get query IR (Intermediate Representation)
ir = qs.query()
print(ir)
# Execution plan
plan = await qs.explain()
print(plan)
# With analyze
plan = await qs.explain(analyze=True)
Multiple Databases
# Use replica for reading
users = await User.objects.filter(is_active=True).all(using="replica")
# Write to master
user = await User.objects.create(name="John", using="master")
Lookup Operators
| Lookup |
Description |
Example |
field |
Equality |
age=18 |
field__exact |
Exact equality (same as =) |
name__exact="John" |
field__iexact |
Case-insensitive equality |
email__iexact="TEST@EXAMPLE.COM" |
field__contains |
Contains (LIKE '%...%') |
name__contains="oh" |
field__icontains |
Case-insensitive contains |
name__icontains="OH" |
field__startswith |
Starts with |
name__startswith="Jo" |
field__istartswith |
Case-insensitive starts with |
name__istartswith="jo" |
field__endswith |
Ends with |
email__endswith="@example.com" |
field__iendswith |
Case-insensitive ends with |
email__iendswith="@EXAMPLE.COM" |
field__gt |
Greater than (>) |
age__gt=18 |
field__gte |
Greater than or equal (>=) |
age__gte=18 |
field__lt |
Less than (<) |
age__lt=65 |
field__lte |
Less than or equal (<=) |
age__lte=65 |
field__in |
In list |
status__in=["active", "premium"] |
field__isnull |
NULL check |
deleted_at__isnull=True |
field__range |
Between (BETWEEN) |
age__range=(18, 65) |
field__between |
Alias for range |
age__between=(18, 65) |
field__year |
Year from date |
created_at__year=2024 |
field__month |
Month from date |
created_at__month=(2024, 12) |
field__day |
Day from date |
created_at__day=(2024, 12, 25) |
Best Practices
DO
# Reuse Query for multiple operations
active = User.objects.filter(is_active=True)
count = await active.count()
users = await active.all()
# Use bulk operations for performance
await User.objects.bulk_create([user1, user2, user3])
# Use prefetch to load related objects
users = await User.objects.prefetch("posts").all()
# Use F() for atomic updates
await Post.objects.filter(id=42).update(views=F("views") + 1)
# Check existence with exists(), not count()
if await User.objects.filter(email=email).exists():
...
DON'T
# Don't query in a loop
users = await User.objects.all()
for user in users:
posts = await Post.objects.filter(author_id=user.id).all() # ❌ Multiple queries
# Use prefetch instead:
users = await User.objects.prefetch("posts").all() # ✅ Two queries total
# Don't save() in a loop for bulk updates
for user in users:
user.status = "archived"
await user.save() # ❌
# Use bulk_update or update():
await User.objects.filter(id__in=ids).update(status="archived") # ✅
# Don't forget .all() for Query
users = await User.objects.filter(is_active=True) # ❌ Returns Query
users = await User.objects.filter(is_active=True).all() # ✅
Architecture Notes
Query Builder (Lazy Evaluation)
# These methods DON'T execute SQL, they just build Query
qs = User.objects.filter(is_active=True) # Query object
qs = qs.prefetch("posts") # Query object
qs = qs.order_by("-created_at") # Query object
# SQL executes only on terminal method call
users = await qs.all() # ← SELECT executes here
Prefetch vs Join
# join() - for FK (single query with JOIN)
posts = await Post.objects.join("author").all()
# SQL: SELECT * FROM posts JOIN users ON ...
# prefetch() - for reverse FK / M2M (separate query)
users = await User.objects.prefetch("posts").all()
# SQL: SELECT * FROM users;
# SELECT * FROM posts WHERE author_id IN (...);
Next Steps