Skip to content

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.