Skip to content

Metadata

Every mutation of any object creates metadata — a record of who changed what and when. Metadata is managed by the framework; you can read it and use it in queries but cannot modify it directly.

Accessing Metadata

metadata = person.get_metadata()
print(metadata.is_deleted)    # False
print(metadata.created_at)    # 1709712000000 (ms since epoch)
metadata = await person.aget_metadata()
print(metadata.is_deleted)
print(metadata.created_at)

Filtering by Metadata

Use the _metadata prefix in queries:

# Soft-deleted records
Person.objects.filter(_metadata__is_deleted=True)

# Records created in the last 24 hours
from datetime import datetime, timedelta

Person.objects.filter(
    _metadata__created_at__gt=datetime.now() - timedelta(hours=24),
)

See Field Lookups for the full list of available metadata fields.

Address

Every record has an address that uniquely identifies it in the database — connection name, class name, class version, object ID, and object version.

person = Person(first_name="Jane")
person.save()
person.last_name = "Roe"
person.save()

latest, old = Person.objects.using(
    'lakehouse',
).order_by('-_metadata__updated_at').execute()

# Same object_id, different object_version
old_addr = old.get_metadata().address
new_addr = latest.get_metadata().address

old_addr.object_id == new_addr.object_id          # True
old_addr.object_version != new_addr.object_version  # True
person = Person(first_name="Jane")
await person.asave()
person.last_name = "Roe"
await person.asave()

latest, old = await Person.objects.using(
    'lakehouse',
).order_by('-_metadata__updated_at').aexecute()

old_addr = (await old.aget_metadata()).address
new_addr = (await latest.aget_metadata()).address

old_addr.object_id == new_addr.object_id          # True
old_addr.object_version != new_addr.object_version  # True

Version History

Every save creates a new version. Versions are linked via prior_version and next_version:

  • First version: prior_version is None
  • Latest version: next_version is None
old_meta = old.get_metadata()
latest_meta = latest.get_metadata()

# First version → no prior, has next
old_meta.prior_version                                      # None
old_meta.next_version == latest_meta.address.object_version  # True

# Latest version → has prior, no next
latest_meta.prior_version == old_meta.address.object_version  # True
latest_meta.next_version                                      # None
old_meta = await old.aget_metadata()
latest_meta = await latest.aget_metadata()

old_meta.prior_version                                      # None
old_meta.next_version == latest_meta.address.object_version  # True

latest_meta.prior_version == old_meta.address.object_version  # True
latest_meta.next_version                                      # None

References

Metadata tracks relationships between objects via reference_to and referenced_by — both are lists of Reference objects.

jane = Person(first_name="Jane")
jane.save()

location = Location(name="New York")
location.save()

# No references yet
jane.get_metadata().reference_to      # []
location.get_metadata().referenced_by  # []

# Create a reference
jane.location = location
jane.save()

# Jane references location
jane.get_metadata().reference_to      # [Reference(...Location...)]
jane.get_metadata().referenced_by     # []

# Location is referenced by jane
location.get_metadata().referenced_by  # [Reference(...Person...)]
location.get_metadata().reference_to   # []
jane = Person(first_name="Jane")
await jane.asave()

location = Location(name="New York")
await location.asave()

meta = await jane.aget_metadata()
meta.reference_to      # []

jane.location = location
await jane.asave()

meta = await jane.aget_metadata()
meta.reference_to      # [Reference(...Location...)]

loc_meta = await location.aget_metadata()
loc_meta.referenced_by  # [Reference(...Person...)]

Timestamps

Each record has created_at and updated_at timestamps (milliseconds since epoch). Different versions of the same object share created_at but have different updated_at:

person = Person(first_name="Jane")
person.save()

initial_created = person.get_metadata().created_at
initial_updated = person.get_metadata().updated_at

person.last_name = "Roe"
person.save()

person.get_metadata().created_at == initial_created  # True — same
person.get_metadata().updated_at > initial_updated   # True — newer
person = Person(first_name="Jane")
await person.asave()

meta = await person.aget_metadata()
initial_created = meta.created_at
initial_updated = meta.updated_at

person.last_name = "Roe"
await person.asave()

meta = await person.aget_metadata()
meta.created_at == initial_created  # True
meta.updated_at > initial_updated   # True