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
def canonical_sqid_prefix(prefix: str) -> strReturn prefix carrying Angee's public-id separator (abc -> abc_).
encode_public_id
def encode_public_id(sqids: Sqids, prefix: str, value: Any) -> strReturn 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
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__
def __init__(*args: Any, prefix: str = "", **kwargs: Any) -> NoneNormalize Angee public-id prefixes to the canonical abc_ shape.
contribute_to_class
def contribute_to_class(cls: type[models.Model], name: str) -> NoneResolve 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
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
def from_db_value(value: Any, expression: Any, connection: Any, *args:
Any) -> AnyReturn 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
def public_id_from_value(value: Any) -> strReturn the encoded public id for one backing integer value.
public_id_to_value
def public_id_to_value(public_id: Any) -> int | NoneReturn the backing integer decoded from one public id.
StateField
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__
def __init__(**kwargs: Any) -> NoneDefault a state column to indexed; it is what queries filter on.
to_python
def to_python(value: Any) -> AnyAccept stored values and GraphQL enum member names for this state.
pre_save
def pre_save(model_instance: models.Model, add: bool) -> AnyNormalize the in-memory value before Django writes and returns it.
FractionalRankExhausted
class FractionalRankExhausted(ValueError)Raised when binary64 cannot represent another safe fractional rank.
FractionalRankField
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__
def __init__(*args: Any, **kwargs: Any) -> NoneDefault ranks to indexed because ordered contexts query by them.
has_default
def has_default() -> boolExpose 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
def get_default() -> NoneSeed an omitted model value for model-owned append allocation.
validate
def validate(value: Any, model_instance: models.Model) -> NoneAllow the pending None that pre_save replaces with a rank.
pre_save
def pre_save(model_instance: models.Model, add: bool) -> floatHonor an explicit rank or append within the model's unique context.
to_python
def to_python(value: Any) -> float | NoneCoerce a rank and reject NaN or infinity at validation boundaries.
get_prep_value
def get_prep_value(value: Any) -> float | NoneReject non-finite ranks on every ORM write path.
get_append_rank
@classmethod
def get_append_rank(cls, previous: float | None) -> floatReturn the initial rank, or one clean step after previous.
get_rank_between
@classmethod
def get_rank_between(cls, previous: float | None,
following: float | None) -> floatReturn 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
def rebalance(*, context: Mapping[str, Any], using: str | None = None) -> intRewrite 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
class _InvalidEncryptedValue()Row-local marker for ciphertext that cannot be decrypted.
__init__
def __init__(label: str | None) -> NoneStore the field label for the eventual access error.
error
def error() -> ImproperlyConfiguredReturn the actionable error for this unreadable value.
__repr__
def __repr__() -> strReturn a safe debug representation without exposing ciphertext.
_EncryptedFieldDescriptor
class _EncryptedFieldDescriptor(DeferredAttribute)Descriptor that isolates decrypt failures to field access.
__set__
def __set__(instance: models.Model, value: Any) -> NoneStore assigned values where Django expects concrete field data.
__get__
def __get__(instance: models.Model | None,
cls: type[models.Model] | None = None) -> AnyReturn the plaintext value or raise the row-local decrypt error.
EncryptedField
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__
def __init__(*args: Any, **kwargs: Any) -> NoneReject uniqueness contracts Fernet ciphertext cannot enforce.
contribute_to_class
def contribute_to_class(cls: type[models.Model],
name: str,
private_only: bool = False) -> NoneStore the deterministic per-column label once Django binds the field.
get_db_prep_save
def get_db_prep_save(value: Any, connection: Any) -> str | NoneEncrypt plaintext for storage in the database column.
from_db_value
def from_db_value(value: str | None, expression: Any,
connection: Any) -> str | _InvalidEncryptedValue | NoneDecrypt database tokens back to plaintext.
get_lookup
def get_lookup(lookup_name: str) -> AnyAllow null checks only; encrypted values are not comparable.
__getattr__
def __getattr__(name: str) -> AnyResolve a field class that moved to another base module (PEP 562).
enum_member_for
def enum_member_for(choices_enum: Any, value: Any) -> Any | NoneReturn the enum member represented by value or None when unknown.