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_versionisNone - Latest version:
next_versionisNone
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