DM + SQL storage how-to#
In diesem Leitfaden wird gezeigt, wie DM-Modelle mit RESTAlchemy in einer SQL-Datenbank gespeichert werden.
Sie lernen:
- DM-Modelle mit
ModelWithUUIDundSQLStorableMixinzu definieren. - Einen SQL-Engine (MySQL oder PostgreSQL) zu konfigurieren.
- CRUD-Operationen mit
.save(),.delete()undModel.objectsauszuführen. - Filter für Abfragen zu verwenden.
Die Beispiele basieren auf examples/dm_mysql_storage.py und examples/dm_pg_storage.py.
Voraussetzungen#
- RESTAlchemy ist installiert (siehe
installation.md). - Eine laufende Datenbank:
- MySQL/MariaDB oder
- PostgreSQL.
- Passender Python-Treiber, z.B.:
mysql-connector-pythonfür MySQL.psycopg[binary]für PostgreSQL.- Tabellen wurden entsprechend den Modell-Definitionen angelegt (siehe Migrationen).
1. DM-Modelle für SQL definieren#
Muster für ein SQL-gestütztes Modell:
- Von
models.ModelWithUUID(oderModelWithID) erben. - Zusätzlich von
orm.SQLStorableMixinerben. __tablename__setzen.- Felder mit DM-Properties und Types definieren.
Beispiel (vereinfacht aus dm_mysql_storage.py):
from restalchemy.dm import models, properties, relationships, types
from restalchemy.storage.sql import orm
class FooModel(models.ModelWithUUID, orm.SQLStorableMixin):
__tablename__ = "foos"
foo_field1 = properties.property(types.Integer(), required=True)
foo_field2 = properties.property(types.String(), default="foo_str")
class BarModel(models.ModelWithUUID, orm.SQLStorableMixin):
__tablename__ = "bars"
bar_field1 = properties.property(types.String(min_length=1, max_length=10))
foo = relationships.relationship(FooModel)
2. SQL-Engine konfigurieren#
Nutzen Sie restalchemy.storage.sql.engines.engine_factory, um eine Engine zu erstellen.
MySQL-Beispiel#
from restalchemy.storage.sql import engines
engines.engine_factory.configure_factory(
db_url="mysql://user:password@127.0.0.1:3306/test",
)
PostgreSQL-Beispiel#
from restalchemy.storage.sql import engines
engines.engine_factory.configure_factory(
db_url="postgresql://postgres:password@127.0.0.1:5432/ra_tests",
)
configure_factory() sollte einmal beim Start des Programms aufgerufen werden. Danach beziehen alle SQLStorableMixin-Modelle die Engine über engine_factory.get_engine().
Optionale Parameter:
config— Engine-spezifische Einstellungen (Poolgrößen, Timeouts usw.).query_cache— aktiviert Query-Caching auf Session-Ebene.
3. Tabellen und Migrationen#
RESTAlchemy legt Tabellen nicht automatisch an; dazu dient das Migrationssystem.
Wichtige Befehle (siehe README.rst):
ra-new-migration— neue Migrationsdateien erzeugen.ra-apply-migration— Migrationen anwenden.
Die Beispiele enthalten auskommentierte SQL-Schemata, etwa in dm_mysql_storage.py:
CREATE TABLE `foos` (
`uuid` CHAR(36) NOT NULL,
`foo_field1` INT NOT NULL,
`foo_field2` VARCHAR(255) NOT NULL,
PRIMARY KEY (`uuid`)
) ENGINE = InnoDB;
CREATE TABLE `bars` (
`uuid` CHAR(36) NOT NULL,
`bar_field1` VARCHAR(10) NOT NULL,
`foo` CHAR(36) NOT NULL,
CONSTRAINT `_idx_foo` FOREIGN KEY (`foo`) REFERENCES `foos`(`uuid`)
) ENGINE = InnoDB;
Sie können diese Schemata an Ihre Umgebung anpassen oder Migrationen erzeugen, die vergleichbares DDL produzieren.
4. CRUD-Operationen#
Erstellen und speichern#
foo1 = FooModel(foo_field1=10)
foo1.save() # INSERT in foos
bar1 = BarModel(bar_field1="test", foo=foo1)
bar1.save() # INSERT in bars
Daten lesen#
# Alle Bars
all_bars = list(BarModel.objects.get_all())
# Ein Bar per Primärschlüssel
same_bar = BarModel.objects.get_one(filters={"uuid": bar1.get_id()})
# Alle Bars für ein bestimmtes FooModel
bars_for_foo = list(BarModel.objects.get_all(filters={"foo": foo1}))
# Als Dictionary
print(bar1.as_plain_dict())
Aktualisieren#
foo2 = FooModel(foo_field1=11, foo_field2="some text")
foo2.save()
foo2.foo_field2 = "updated text"
foo2.save() # UPDATE
Löschen#
5. Filter#
Filter kommen aus restalchemy.dm.filters und werden an get_all() / get_one() übergeben.
Einfache Filter#
from restalchemy.dm import filters
one = FooModel.objects.get_one(filters={"foo_field1": filters.EQ(10)})
greater = list(
FooModel.objects.get_all(filters={"foo_field1": filters.GT(5)})
)
subset = list(
FooModel.objects.get_all(filters={"foo_field1": filters.In([5, 6])})
)
not_subset = list(
FooModel.objects.get_all(filters={"foo_field1": filters.NotIn([1, 2])})
)
Komplexe Ausdrücke#
from restalchemy.dm import filters
filter_expr = filters.OR(
filters.AND({
"foo_field1": filters.EQ(1),
"foo_field2": filters.EQ("2"),
}),
filters.AND({"foo_field2": filters.EQ("3")}),
)
foo = FooModel.objects.get_one(filters=filter_expr)
6. Transaktionen und Sessions#
Standardmäßig verwendet jede Operation eine eigene Session und Transaktion.
Für zusammenhängende Operationen in einer Transaktion können Sie engine.session_manager() verwenden.
engine.session_manager() verwenden#
from restalchemy.storage.sql import engines
engine = engines.engine_factory.get_engine()
with engine.session_manager() as session:
foo = FooModel(foo_field1=42)
foo.save(session=session)
bar = BarModel(bar_field1="x", foo=foo)
bar.save(session=session)
# Tritt hier ein Fehler auf, werden beide INSERTs zurückgerollt.
Innerhalb des with-Blocks teilen sich alle Operationen dieselbe Session und Transaktion.
Sie können ein von der Engine bezogenes Session-Objekt auch an anderer Stelle weiterverwenden, indem Sie session= an .save(), .delete() oder an Collection-Methoden übergeben.
Zusammenfassung#
- DM-Modelle:
ModelWithUUID+SQLStorableMixin+__tablename__. - Engine-Konfiguration:
engine_factory.configure_factory(). - Tabellen/Migrationen: über
ra-*-Befehle. - CRUD:
.save(),.delete(),Model.objects.get_all()/get_one(). - Filter:
restalchemy.dm.filters. - Transaktionen: bei Bedarf über explizite Sessions.