Skip to content

angee.base.refs

Generic record references backed by Django contenttypes.

Also the owner of the record-target-across-MTI policy: a polymorphic edge and a REBAC grant see a multi-table-inheritance row from different sides. :func:canonical_record_model and :func:canonical_record_target own the write identity; :func:ancestor_object_refs owns the read/grant fan-out.

Placement invariant. A polymorphic edge that keys on :func:canonical_record_targetstorage.FileAttachment, tags.TagAssignment, messaging.ThreadAttachment, knowledge.RecordBinding, and every reverse GenericRelation onto such an edge (messaging.ThreadedModelMixin.thread_attachments, a future tags relation on Party) — must be declared on, and any mixin owning it composed onto, the same topmost REBAC-typed MTI ancestor the canonical write keys on. A reverse GenericRelation filters at its declaring model's own content type, so composing the mixin on a child while its canonical ancestor does not splits the write content type from the collect content type and orphans edge rows on delete.

RecordRef

python
@dataclass(frozen=True, slots=True)
class RecordRef()

Frozen public identity for a model row reached through a generic pointer.

record_ref_for

python
def record_ref_for(instance: models.Model) -> RecordRef

Return the stable public reference for instance.

CanonicalRecordTarget

python
class CanonicalRecordTarget(NamedTuple)

The content type and id a polymorphic edge must store for a target row.

canonical_record_target

python
def canonical_record_target(obj: models.Model) -> CanonicalRecordTarget

Return the content type and id a polymorphic edge must store for obj.

The write rule for a generic foreign key across multi-table inheritance: resolve obj to its concrete model first (unwrapping any proxy), then canonicalize to the topmost concrete MTI ancestor that declares a rebac_resource_type — a parties.Person row canonicalizes to its parties.Party ancestor — so a child and its parent share one edge set instead of splitting it across their two content types. Resolving the proxy first means an untyped proxy over a typed concrete row keys on the typed concrete ancestor, never the proxy's own content type: a proxy is a presentation of its concrete row, not a distinct target (this replaces the earlier "keep the proxy's own content type" behavior). A row with no REBAC-typed ancestor keys on its concrete content type. MTI shares one primary key down the pk-link chain, so obj.pk addresses the row at whichever ancestor owns the edge; :func:ancestor_object_refs is the dual that reads every level back.

ancestor_object_refs

python
def ancestor_object_refs(obj: models.Model) -> tuple[ObjectRef, ...]

Return every REBAC identity obj IS-A, nearest identity first.

The read/grant fan-out dual of :func:canonical_record_target: obj's own identity first (raises :class:TypeError if its model declares no rebac_resource_type), then each REBAC-registered concrete MTI ancestor it shares a primary key with (parties.Person IS-A parties.Party). Every identity shares obj's REBAC id, so a grant or read on any ancestor type reaches the same row — the reason a foreign key typed to a parent still scopes the child in. Returned eagerly as a tuple, so the fail-fast fires at the call rather than on first iteration.

canonical_record_model

python
def canonical_record_model(model: type[models.Model]) -> type[models.Model]

Return the topmost concrete MTI ancestor of model with a REBAC type.

This is the model-class projection of :func:canonical_record_target, for callers such as resource metadata that need the canonical label without an instance or a contenttypes query. Proxies unwrap first; untyped rows fall back to their concrete model.

RecordRefMixin

python
class RecordRefMixin(models.Model)

Project a contenttypes-backed row reference from model-owned fields.

record_ref_field_prefix

Reference field prefix; target maps to content_type/object_id.

Meta

python
class Meta()

Django model options for record-ref-only abstract inheritance.

record_ref

python
@property
def record_ref() -> RecordRef

Return this row's referenced record identity without loading the target.

record_model_label

python
@property
def record_model_label() -> str

Return the referenced record's app_label.ModelName label.

record_public_id

python
@property
def record_public_id() -> str

Return the referenced record's stable public id.

Released under the AGPL-3.0 License.