F-Expressions¶
F expressions reference database columns for atomic operations executed entirely in the database.
Why F Expressions?¶
Without F expressions, you risk race conditions:
# BAD: Race condition
post = await Post.objects.get(id=1)
post.views = post.views + 1 # Read old value
await post.save() # Another request might have incremented too
With F expressions, the operation is atomic:
The SQL generated is UPDATE posts SET views = views + 1 WHERE id = 1.
Basic Usage¶
from oxyde import F
# Reference a column
F("views")
# Arithmetic
F("views") + 1
F("price") * 0.9
F("balance") - 100
F("total") / F("count")
Supported Operations¶
| Operation | Example | SQL |
|---|---|---|
| Addition | F("x") + 1 |
x + 1 |
| Subtraction | F("x") - 1 |
x - 1 |
| Multiplication | F("x") * 2 |
x * 2 |
| Division | F("x") / 2 |
x / 2 |
| Negation | -F("x") |
-x |
Column + Column¶
Combine multiple columns:
# total = price * quantity
await Order.objects.filter(id=1).update(total=F("price") * F("quantity"))
# score = base_score + bonus
await Player.objects.filter(id=1).update(score=F("base_score") + F("bonus"))
Use with update()¶
The most common use case:
# Increment
await Post.objects.filter(id=1).update(views=F("views") + 1)
# Decrement
await Product.objects.filter(id=1).update(stock=F("stock") - 1)
# Percentage increase
await Product.objects.filter(category="sale").update(
price=F("price") * 1.1 # 10% increase
)
# Percentage discount
await Product.objects.filter(category="clearance").update(
price=F("price") * 0.5 # 50% off
)
Use with increment()¶
Shortcut for common increment pattern:
# These are equivalent:
await Post.objects.filter(id=1).update(views=F("views") + 1)
await Post.objects.filter(id=1).increment("views", by=1)
# Decrement
await Post.objects.filter(id=1).increment("views", by=-1)
Bulk Updates¶
F expressions work with bulk updates:
# Give everyone a 5% raise
await Employee.objects.update(salary=F("salary") * 1.05)
# Reset all counters
await Stats.objects.update(count=F("count") * 0) # Set to 0
Complex Expressions¶
Chain operations:
# (price * quantity) - discount
await Order.objects.filter(id=1).update(
total=F("price") * F("quantity") - F("discount")
)
# Nested: ((base + bonus) * multiplier)
await Score.objects.filter(id=1).update(
final=((F("base") + F("bonus")) * F("multiplier"))
)
With Value Constants¶
Mix F expressions with constants:
# Add flat fee
await Order.objects.filter(id=1).update(total=F("subtotal") + 9.99)
# Apply tax rate
await Order.objects.filter(id=1).update(total=F("subtotal") * 1.08)
Reverse Operations¶
F expressions support reverse operations:
# 100 - balance (instead of balance - 100)
await Account.objects.filter(id=1).update(remaining=100 - F("spent"))
# 2 * multiplier
await Score.objects.filter(id=1).update(doubled=2 * F("base"))
Examples¶
Page View Counter¶
Inventory Management¶
async def purchase(product_id: int, quantity: int):
await Product.objects.filter(id=product_id).update(
stock=F("stock") - quantity
)
async def restock(product_id: int, quantity: int):
await Product.objects.filter(id=product_id).update(
stock=F("stock") + quantity
)
Balance Transfer¶
from oxyde.db import transaction
async def transfer(from_id: int, to_id: int, amount: float):
async with transaction.atomic():
await Account.objects.filter(id=from_id).update(
balance=F("balance") - amount
)
await Account.objects.filter(id=to_id).update(
balance=F("balance") + amount
)
Pricing Rules¶
# Apply 20% discount to all sale items
await Product.objects.filter(on_sale=True).update(
price=F("price") * 0.8
)
# Round up to nearest dollar
await Product.objects.update(
price=F("price") + 0.99 # Simple approach
)
Score Calculation¶
Limitations¶
No Filtering with F¶
F expressions are for UPDATE values, not for filtering:
# This won't work
# await User.objects.filter(balance__gt=F("credit_limit")).all()
# Use raw SQL or application logic instead
No String Operations¶
F expressions only support numeric operations:
# These won't work:
# F("first_name") + " " + F("last_name") # String concat
# F("name").lower() # String methods
# Use database functions or compute in application
Read-Only in Select¶
F expressions are primarily for UPDATE statements. For computed columns in SELECT, use annotations with aggregate functions.
Next Steps¶
- Aggregation — Aggregate functions and GROUP BY
- Queries — Full query reference
- Transactions — Atomic operations with transactions