Source code for ferrosoft.apps.ferrobase.forms.fields

#  Copyright (c) 2025 Ferrosoft GmbH. All rights reserved.
from itertools import groupby
from uuid import UUID

from django import forms
from django.utils.choices import BaseChoiceIterator

from ferrosoft.apps.ferrobase.models import (
    UnitCursor,
    UnitSystem,
)
from ferrosoft.apps.ferrobase.models.registry import ModelRegistry


[docs] class UnitChoiceIterator(BaseChoiceIterator): """Choice iterator for measurement units (reserved for future use)."""
[docs] class UnitChoiceField(forms.ChoiceField): """Choice field that presents measurement units grouped by unit system. Units are looked up from ``ModelRegistry.Unit`` and rendered as an ``<optgroup>`` per ``UnitSystem`` (Metric, US Customary, Imperial). The field converts a submitted UUID string back to a ``MeasurementUnit`` instance via ``to_python``. Args: units: Iterable of ``UnitCursor`` objects defining the selectable units. initial: Optional ``UnitCursor`` whose matching database unit is pre-selected. """ def __init__(self, *args, **kwargs): self.registry = ModelRegistry.Unit units = kwargs.pop("units") choices = [ ( UnitSystem(system).label, [ (str(unit.id), str(unit)) for unit in sorted(units, key=lambda unit: unit.symbol) ], ) for system, units in groupby( self.registry.find(units), key=lambda unit: unit.system ) ] kwargs.update( { "choices": choices, "initial": self._get_initial(kwargs.pop("initial", None)), } ) super().__init__(*args, **kwargs)
[docs] def to_python(self, value): """Convert a UUID string from the form submission to a ``MeasurementUnit``. Args: value: UUID string identifying the selected unit. Returns: MeasurementUnit: The corresponding unit instance from the registry. """ return self.registry.get(UUID(value))
[docs] def valid_value(self, value): """Check that the submitted value identifies a known unit. Args: value: UUID string to validate. Returns: bool: ``True`` if the registry contains a unit with this UUID. """ return self.registry.exists(value)
def _get_initial(self, cursor: UnitCursor | None): def find(): if cursor is None: return None unit = self.registry.get(cursor) if unit is None: return None return str(unit.id) return find