Skip to content

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 ModelWithUUID und SQLStorableMixin zu definieren.
  • Einen SQL-Engine (MySQL oder PostgreSQL) zu konfigurieren.
  • CRUD-Operationen mit .save(), .delete() und Model.objects auszufü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-python fü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 (oder ModelWithID) erben.
  • Zusätzlich von orm.SQLStorableMixin erben.
  • __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#

for foo in FooModel.objects.get_all():
    foo.delete()

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.