Queries¶
Every model has an objects manager that returns QuerySet objects for building database queries.
Person.objects.all()
Person.objects.filter(name='John')
Person.objects.get(first_name='John', last_name='Doe')
QuerySet¶
A QuerySet is an immutable query builder. Each method returns a new QuerySet, so you can chain methods freely:
qs = Person.objects.filter(name='John').filter(age=20)
# Equivalent — multiple kwargs are ANDed:
qs = Person.objects.filter(name='John', age=20)
For OR conditions, use the Q object:
from amsdal.queryset import Q
qs = Person.objects.filter(Q(name='John') | Q(age=20))
Executing Queries¶
A QuerySet is not evaluated until you call execute() / aexecute():
persons = Person.objects.filter(name='John').execute()
persons = await Person.objects.filter(name='John').aexecute()
Available Methods¶
| Method | Returns | Description |
|---|---|---|
all() |
QuerySet | No filters |
filter(*args, **kwargs) |
QuerySet | Include matching records |
exclude(*args, **kwargs) |
QuerySet | Exclude matching records |
get(*args, **kwargs) |
QuerySetOneRequired | Exactly one result or raises error |
get_or_none(*args, **kwargs) |
QuerySetOne | One result or None |
first(*args, **kwargs) |
QuerySetOne | First matching result or None |
count() |
QuerySetCount | Returns int on execute() |
order_by(*fields) |
QuerySet | Sort results. Prefix with - for descending |
distinct(fields) |
QuerySet | Unique results by given field list |
only(fields) |
QuerySet | Load only specified fields (partial models) |
select_related(*fields) |
QuerySet | Eager-load related objects |
using(alias) |
QuerySet | Use a specific connection |
latest() |
QuerySet | Filter to latest versions only |
none() |
QuerySet | Empty QuerySet (no DB hit) |
annotate(**kwargs) |
QuerySet | Add annotations to the query |
decrypt_pii() |
QuerySet | Decrypt PII fields in results |
Counting¶
count() returns a QuerySetCount — call execute() to get the int:
total = Person.objects.filter(name='John').count().execute()
total = await Person.objects.filter(name='John').count().aexecute()
Ordering¶
Use - prefix for descending order:
Person.objects.order_by('name') # A → Z
Person.objects.order_by('-created_at') # newest first
Person.objects.order_by('name', '-age') # multiple fields
Pagination (Slicing)¶
Use Python slice syntax for limit/offset:
# First 10 results
Person.objects.all()[0:10].execute()
# Skip 20, get 10
Person.objects.all()[20:30].execute()
Multiple Connections¶
AMSDAL supports multiple connections per model — a default (state) connection and a lakehouse connection for historical data.
qs = Person.objects.using('lakehouse').filter(name='John')
With the lakehouse connection you can filter by object and class versions:
from amsdal import Versions
persons = Person.objects.using('lakehouse').filter(
name='John',
_address__object_version=Versions.LATEST,
).execute()
from amsdal import Versions
persons = await Person.objects.using('lakehouse').filter(
name='John',
_address__object_version=Versions.LATEST,
).aexecute()
Info
See Configuration for how to set up connections.