Skip to content

angee.base.fields

Angee model field types.

Thin semantic wrappers over the libraries docs/stack.md names as the owner of each concern. Angee adds only the naming and the framework default; the library owns the behavior.

Fields may also declare projection facts for data-resource metadata: angee_widget, angee_scalar_hint, and angee_currency_field. The GraphQL classifier reads those inert attributes before falling back to stock Django field types, so a field's owner states its own wire vocabulary.

FractionalRankField is the framework's manual-ordering contract. An ordered row stores one finite binary64 rank; its model defines the surrounding context and must enforce UniqueConstraint(fields=(*context_fields, rank_field)) (nulls_distinct=False when a context field is nullable). Append with get_append_rank(last_rank) and insert or move with get_rank_between(previous_rank, next_rank). Ranks start and rebalance at 1024.0 intervals, a power-of-two spread whose midpoints stay exact until the available binary64 values are genuinely exhausted. FractionalRankExhausted is the signal to enqueue the durable jobs.rebalance_fractional_ranks task with the concrete model label, exact context values, and rank-field name; callers must not guess an epsilon or silently reuse a rank. Rebalance rewrites only that context under one transaction, preserves its visible (rank, pk) order, and is idempotent. Allocation is optimistic: the contextual unique constraint arbitrates concurrent writers, and a losing writer rereads its neighbors before retrying.

canonical_sqid_prefix

python
def canonical_sqid_prefix(prefix: str) -> str

Return prefix carrying Angee's public-id separator (abc -> abc_).

encode_public_id

python
def encode_public_id(sqids: Sqids, prefix: str, value: Any) -> str

Return the public id encoding value's backing integer under prefix.

The one reading of "encode a primary-key value to an Angee public id" — the shared body behind SqidField.public_id_from_value. prefix is already canonical.

SqidField

python
class SqidField(SqidsField)

Angee's opaque public id column, declared as django-sqids glue.

docs/stack.md names django-sqids the owner of opaque external ids; this wrapper makes the decoder total and lets a model state only the one fact that varies between models — the prefix. A model declares sqid_prefix = "nte_" (SqidMixin exposes the attribute and the shared column); the field reads it in contribute_to_class rather than every model re-declaring the whole column. An explicit prefix= still wins.

Totality: from_db_value receives None when the encoded column arrives through a nullable join — e.g. values_list("parent__sqid") over a nullable self-FK, the shape REBAC field-backed arrows query — and upstream encodes unconditionally there.

The field is also usable unbound as a pure public-id codec through public_id_from_value and public_id_to_value; third-party-model adapters such as SqidPublicIdentity build on that declared API.

__init__

python
def __init__(*args: Any, prefix: str = "", **kwargs: Any) -> None

Normalize Angee public-id prefixes to the canonical abc_ shape.

contribute_to_class

python
def contribute_to_class(cls: type[models.Model], name: str) -> None

Resolve the prefix from the model's <field>_prefix when unset.

Lets SqidMixin's one shared column serve every model: each model states only sqid_prefix = "nte_" and the inherited field picks it up here. sqid is a private, non-concrete column, so this never reaches a migration — it only shapes how the id encodes.

deconstruct

python
def deconstruct() -> tuple[str | None, str, list[Any], dict[str, Any]]

Serialize the full public-id contract for generated/runtime models.

Emits the resolved prefix (not the declared one), so an emitted or migration-state model carries the full prefix without needing the source's sqid_prefix class attribute.

from_db_value

python
def from_db_value(value: Any, expression: Any, connection: Any, *args:
                  Any) -> Any

Return the encoded public id, passing NULL columns through.

django_sqids from_db_value encodes unconditionally, so a NULL arriving through a nullable join crashes it (sqids.encode([None]) raises TypeError); this guard is the workaround. The durable fix is an upstream django_sqids PR, after which this override can be deleted.

public_id_from_value

python
def public_id_from_value(value: Any) -> str

Return the encoded public id for one backing integer value.

public_id_to_value

python
def public_id_to_value(public_id: Any) -> int | None

Return the backing integer decoded from one public id.

StateField

python
class StateField(TextChoicesField)

A finite-state column backed by a TextChoices enum.

docs/stack.md names django-choices-field the owner of enum-backed model fields; this is the StateField semantic wrapper it lists. The enum is the single source of truth — strawberry-django emits the GraphQL enum straight from choices_enum and the column max_length is derived from it, so a state column never restates its choices. Declared natively, e.g. StateField(choices_enum=Note.Status, default=...).

__init__

python
def __init__(**kwargs: Any) -> None

Default a state column to indexed; it is what queries filter on.

to_python

python
def to_python(value: Any) -> Any

Accept stored values and GraphQL enum member names for this state.

pre_save

python
def pre_save(model_instance: models.Model, add: bool) -> Any

Normalize the in-memory value before Django writes and returns it.

FractionalRankExhausted

python
class FractionalRankExhausted(ValueError)

Raised when binary64 cannot represent another safe fractional rank.

FractionalRankField

python
class FractionalRankField(models.FloatField)

Finite float rank for manual ordering inside a model-defined context.

The field owns rank arithmetic and transactional rebalance. The consumer model owns the context columns and their database uniqueness constraint; the field cannot infer whether a list is scoped by a lane, parent, project, or another domain fact.

__init__

python
def __init__(*args: Any, **kwargs: Any) -> None

Default ranks to indexed because ordered contexts query by them.

has_default

python
def has_default() -> bool

Expose model-owned append allocation as a server-side default.

Hasura input generation uses Django's field-owned has_default fact to decide whether an insert column may be omitted. A fractional rank has no context-free literal default; pre_save supplies its contextual append rank for every model write path.

get_default

python
def get_default() -> None

Seed an omitted model value for model-owned append allocation.

validate

python
def validate(value: Any, model_instance: models.Model) -> None

Allow the pending None that pre_save replaces with a rank.

pre_save

python
def pre_save(model_instance: models.Model, add: bool) -> float

Honor an explicit rank or append within the model's unique context.

to_python

python
def to_python(value: Any) -> float | None

Coerce a rank and reject NaN or infinity at validation boundaries.

get_prep_value

python
def get_prep_value(value: Any) -> float | None

Reject non-finite ranks on every ORM write path.

get_append_rank

python
@classmethod
def get_append_rank(cls, previous: float | None) -> float

Return the initial rank, or one clean step after previous.

get_rank_between

python
@classmethod
def get_rank_between(cls, previous: float | None,
                     following: float | None) -> float

Return a rank strictly between optional neighboring ranks.

None denotes the corresponding edge: both edges absent returns the initial rank, no following neighbor appends, and no previous neighbor prepends by one clean step.

rebalance

python
def rebalance(*, context: Mapping[str, Any], using: str | None = None) -> int

Rewrite this field to a clean spread inside one exact context.

Returns the number of rows whose rank changed. Rows are read in committed (rank, pk) order through the model's system queryset and staged outside both the old and final ranges before the clean ranks are written. Staging avoids transient unique-constraint collisions. A concurrent insert is arbitrated by that constraint and must retry. The rank must be NOT NULL.

_InvalidEncryptedValue

python
class _InvalidEncryptedValue()

Row-local marker for ciphertext that cannot be decrypted.

__init__

python
def __init__(label: str | None) -> None

Store the field label for the eventual access error.

error

python
def error() -> ImproperlyConfigured

Return the actionable error for this unreadable value.

__repr__

python
def __repr__() -> str

Return a safe debug representation without exposing ciphertext.

_EncryptedFieldDescriptor

python
class _EncryptedFieldDescriptor(DeferredAttribute)

Descriptor that isolates decrypt failures to field access.

__set__

python
def __set__(instance: models.Model, value: Any) -> None

Store assigned values where Django expects concrete field data.

__get__

python
def __get__(instance: models.Model | None,
            cls: type[models.Model] | None = None) -> Any

Return the plaintext value or raise the row-local decrypt error.

EncryptedField

python
class EncryptedField(models.TextField)

Fernet-at-rest text field for framework secret values.

The database stores a Fernet token while Python reads return decrypted plaintext. Each column derives its Fernet key from settings.SECRET_KEY with HKDF-SHA256 using the model's label_lower plus field name as the per-column label. The field is secret-by-type: never put it on a GraphQL type. Fernet is non-deterministic, so the column is not queryable by value; get_or_create()/update_or_create() keyed on it and bulk_update() of it will raise, unique=True/primary_key=True are rejected at construction, and ordering or distinct on the column are meaningless. Today the key tracks SECRET_KEY, so rotating SECRET_KEY orphans existing ciphertext; ANGEE_FERNET_KEYS/MultiFernet is the future rotation path.

__init__

python
def __init__(*args: Any, **kwargs: Any) -> None

Reject uniqueness contracts Fernet ciphertext cannot enforce.

contribute_to_class

python
def contribute_to_class(cls: type[models.Model],
                        name: str,
                        private_only: bool = False) -> None

Store the deterministic per-column label once Django binds the field.

get_db_prep_save

python
def get_db_prep_save(value: Any, connection: Any) -> str | None

Encrypt plaintext for storage in the database column.

from_db_value

python
def from_db_value(value: str | None, expression: Any,
                  connection: Any) -> str | _InvalidEncryptedValue | None

Decrypt database tokens back to plaintext.

get_lookup

python
def get_lookup(lookup_name: str) -> Any

Allow null checks only; encrypted values are not comparable.

__getattr__

python
def __getattr__(name: str) -> Any

Resolve a field class that moved to another base module (PEP 562).

enum_member_for

python
def enum_member_for(choices_enum: Any, value: Any) -> Any | None

Return the enum member represented by value or None when unknown.

Released under the AGPL-3.0 License.