Properties#
Modul: restalchemy.dm.properties
Properties sind der zentrale Mechanismus, mit dem DM-Modelle Felder definieren und Werte speichern.
Basisklassen#
AbstractProperty#
Abstrakte Basisklasse für alle Properties:
value(Property): aktueller Wert.set_value_force(value): Wert setzen unter Umgehung von read-only/ID-Regeln.is_dirty(): zeigt an, ob sich der Wert seit der Initialisierung geändert hat.is_prefetch()(classmethod): ob das Property für Prefetching markiert ist.
Property#
Standard-Implementierung für skalare und strukturierte Felder.
Konstruktor:
Property(
property_type,
default=None,
required=False,
read_only=False,
value=None,
mutable=False,
example=None,
)
Wesentliche Punkte:
property_typemuss eine Instanz vontypes.BaseTypesein.defaultkann ein Wert oder ein Callable sein.- Falls
valuegesetzt ist, überschreibt esdefault. - Bei
mutable=Falsewird der Startwert füris_dirty()tief kopiert. - Ungültige Werte führen zu Exceptions aus
restalchemy.common.exceptions.
IDProperty#
Spezialfall von Property für ID-Felder:
is_id_property()gibtTruezurück.- Wird mit
ModelWithID/ModelWithUUIDkombiniert.
PropertyCreator und Fabriken#
PropertyCreator#
Speichert, wie ein konkretes Property erstellt wird:
- Property-Klasse (
PropertyoderIDProperty). - DM-Typinstanz (
types.String(),types.Integer(), ...). - Argumente und Keyword-Argumente.
prefetch-Flag.
Auf Klassenebene weisen Sie PropertyCreator-Instanzen den Attributen zu.
property()#
Hauptfabrik für Properties in Modellen:
from restalchemy.dm import properties, types
class Foo(models.Model):
value = properties.property(types.Integer(), required=True)
Argumente:
property_type: Instanz vontypes.BaseType.id_property: wennTrue, wirdIDPropertyverwendet.property_class: eigene Property-Klasse (muss vonAbstractPropertyerben).- Weitere Keyword-Argumente werden an den Property-Konstruktor weitergegeben.
Komfort-Fabriken#
required_property(property_type, *args, **kwargs)— setztrequired=True.readonly_property(property_type, *args, **kwargs)— setztread_only=Trueundrequired=True.
Beispiel:
class User(models.ModelWithUUID):
email = properties.required_property(types.Email())
created_at = properties.readonly_property(types.UTCDateTimeZ(), default=datetime.datetime.now)
PropertyCollection und PropertyManager#
PropertyCollection#
- Hält Mapping Name →
PropertyCreator(oder verschachteltePropertyCollection). - Implementiert Mapping-Protokoll.
sort_properties()sortiert Keys alphabetisch.instantiate_property(name, value=None)erzeugt eine konkrete Property-Instanz.
PropertyManager#
Laufzeit-Container für Properties auf Instanzebene:
- Baut konkrete Property-Objekte aus einer
PropertyCollectionund Keyword-Argumenten. properties: read-only Mapping Name → Property.value: Dict mit "rohen" Werten (lesen/schreiben).
Model.pour() verwendet PropertyManager, um den Instanzzustand aufzubauen:
Fehlt eine erforderliche Property, wirft PropertyManager ein PropertyRequired mit dem Feldnamen.
Container und verschachtelte Strukturen#
container()#
Erzeugt eine verschachtelte PropertyCollection für gruppierte Felder:
address_container = properties.container(
city=properties.property(types.String()),
zip_code=properties.property(types.String()),
)
class User(models.ModelWithUUID):
name = properties.property(types.String(), required=True)
address = address_container
Zur Laufzeit ist address ein PropertyManager, z.B.:
Dirty Tracking#
Property und Relationship unterstützen is_dirty():
Propertyvergleicht aktuellen und initialen Wert.Relationshipvergleicht aktuelle und ursprüngliche Relation.
Model.is_dirty() iteriert über alle Properties und gibt True zurück, sobald eines "dirty" ist.
Best Practices#
- Verwenden Sie DM-Typen (
types.String,types.Integeretc.) statt roher Python-Typen. - Markieren Sie ID-Felder mit
id_property=Trueoder nutzen SieModelWithUUID. - Nutzen Sie
required_property()/readonly_property()für bessere Lesbarkeit. - Verwenden Sie
container()für logisch gruppierte Felder oder verschachtelte JSON-Strukturen.