Serverseitige Filterung für Listen-Endpunkte und Einzelabrufe in Listen-Komponenten

Server: Die list-Endpunkte für Kontakt, Projekt, Kontaktadresse und CallLog
akzeptieren nun einen optionalen Query-Parameter (kunden_id bzw. projekt_id)
und filtern im ORM-Query. Neue Migration V01.05 legt Indizes auf den
FK-Spalten an.

Client: Die fetch-Funktionen erhalten einen optionalen Parent-ID-Parameter.
Die Listen-Komponenten übergeben die Parent-ID aus den Route-Params an den
Server und laden nur noch benötigte Daten. Statt kompletter Eltern-Listen
wird per fetchXxxById ein einzelner Datensatz für die Namensauflösung geladen.
Die CallLog-Bearbeitungsmaske behält ihre ungesfilterten Dropdown-Abrufe.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
gg committed 2026-09-04 15:43:43 +02:00
1 parent e9a2f48ede
commit 93827dde0f
15 files changed
+189 -141

No files matched your search

+13 -1
View File
@@ -12,7 +12,7 @@ erfolgt ausschließlich über __bind_key__.
import datetime
import decimal
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Index, Integer, String
from sqlalchemy.orm import relationship
from db import dbapp
@@ -103,6 +103,9 @@ class Kontakt(dbapp.Model):
"""
__tablename__ = 'kontakte'
__bind_key__ = BINDKEY
__table_args__ = (
Index('ix_kontakte_kunden_id', 'kunden_id'),
)
id = Column(Integer, primary_key=True)
kunden_id = Column(Integer, ForeignKey('kunden.id'), nullable=False)
anrede = Column(String(30), nullable=True)
@@ -134,6 +137,9 @@ class Projekt(dbapp.Model):
"""
__tablename__ = 'projekte'
__bind_key__ = BINDKEY
__table_args__ = (
Index('ix_projekte_kunden_id', 'kunden_id'),
)
id = Column(Integer, primary_key=True)
kunden_id = Column(Integer, ForeignKey('kunden.id'), nullable=False)
projektname = Column(String(200), nullable=False)
@@ -163,6 +169,9 @@ class Kontaktadresse(dbapp.Model):
"""
__tablename__ = 'kontaktadressen'
__bind_key__ = BINDKEY
__table_args__ = (
Index('ix_kontaktadressen_projekt_id', 'projekt_id'),
)
id = Column(Integer, primary_key=True)
projekt_id = Column(Integer, ForeignKey('projekte.id'), nullable=False)
anrede = Column(String(30), nullable=True)
@@ -200,6 +209,9 @@ class CallLog(dbapp.Model):
"""
__tablename__ = 'call_logs'
__bind_key__ = BINDKEY
__table_args__ = (
Index('ix_call_logs_projekt_id', 'projekt_id'),
)
id = Column(Integer, primary_key=True)
projekt_id = Column(Integer, ForeignKey('projekte.id'), nullable=False)
datum = Column(String(20), nullable=True)
+10 -3
View File
@@ -17,11 +17,18 @@ from auth.model.errors import ApplicationError, HtmlStatusCode
session = dbapp.session
def get_call_logs():
def get_call_logs(projekt_id: int | None = None):
"""
Liefert alle Gesprächsnotizen, sortiert nach Datum absteigend.
Liefert Gesprächsnotizen, sortiert nach Datum absteigend.
Ist projekt_id gesetzt, werden nur die Notizen dieses Projekts
zurückgegeben (serverseitige Filterung). Ohne projekt_id werden
alle Notizen geliefert.
"""
return CallLog.query.order_by(CallLog.datum.desc()).all()
query = CallLog.query
if projekt_id is not None:
query = query.filter(CallLog.projekt_id == projekt_id)
return query.order_by(CallLog.datum.desc()).all()
def get_call_log(call_log_id: int) -> CallLog:
+17
View File
@@ -91,6 +91,23 @@ def _db_V01_04():
session.commit()
def _db_V01_05():
"""
Legt Indizes auf den Fremdschlüsselspalten an, die für die
serverseitige Filterung der Listen-Endpunkte genutzt werden.
CREATE INDEX IF NOT EXISTS ist idempotent und überspringet bereits
vorhandene Indizes.
"""
from sqlalchemy import text
session.execute(text("CREATE INDEX IF NOT EXISTS ix_kontakte_kunden_id ON kontakte (kunden_id)"))
session.execute(text("CREATE INDEX IF NOT EXISTS ix_projekte_kunden_id ON projekte (kunden_id)"))
session.execute(text("CREATE INDEX IF NOT EXISTS ix_kontaktadressen_projekt_id ON kontaktadressen (projekt_id)"))
session.execute(text("CREATE INDEX IF NOT EXISTS ix_call_logs_projekt_id ON call_logs (projekt_id)"))
_updatesysteminfo('01.05')
session.commit()
def checkupdates():
"""
Ermittelt die aktuelle DB-Version aus der Systeminfo-Tabelle und führt alle
+10 -3
View File
@@ -17,11 +17,18 @@ from auth.model.errors import ApplicationError, HtmlStatusCode
session = dbapp.session
def get_kontakte():
def get_kontakte(kunden_id: int | None = None):
"""
Liefert alle Kontakte, sortiert nach Name.
Liefert Kontakte, sortiert nach Name.
Ist kunden_id gesetzt, werden nur die Kontakte dieses Kunden
zurückgegeben (serverseitige Filterung). Ohne kunden_id werden
alle Kontakte geliefert.
"""
return Kontakt.query.order_by(Kontakt.name).all()
query = Kontakt.query
if kunden_id is not None:
query = query.filter(Kontakt.kunden_id == kunden_id)
return query.order_by(Kontakt.name).all()
def get_kontakt(kontakt_id: int) -> Kontakt:
+10 -3
View File
@@ -17,11 +17,18 @@ from auth.model.errors import ApplicationError, HtmlStatusCode
session = dbapp.session
def get_kontaktadressen():
def get_kontaktadressen(projekt_id: int | None = None):
"""
Liefert alle Kontaktadressen, sortiert nach Name.
Liefert Kontaktadressen, sortiert nach Name.
Ist projekt_id gesetzt, werden nur die Kontaktadressen dieses
Projekts zurückgegeben (serverseitige Filterung). Ohne projekt_id
werden alle Kontaktadressen geliefert.
"""
return Kontaktadresse.query.order_by(Kontaktadresse.name).all()
query = Kontaktadresse.query
if projekt_id is not None:
query = query.filter(Kontaktadresse.projekt_id == projekt_id)
return query.order_by(Kontaktadresse.name).all()
def get_kontaktadresse(kontaktadresse_id: int) -> Kontaktadresse:
+10 -3
View File
@@ -17,11 +17,18 @@ from auth.model.errors import ApplicationError, HtmlStatusCode
session = dbapp.session
def get_projekte():
def get_projekte(kunden_id: int | None = None):
"""
Liefert alle Projekte, sortiert nach projektname.
Liefert Projekte, sortiert nach projektname.
Ist kunden_id gesetzt, werden nur die Projekte dieses Kunden
zurückgegeben (serverseitige Filterung). Ohne kunden_id werden
alle Projekte geliefert.
"""
return Projekt.query.order_by(Projekt.projektname).all()
query = Projekt.query
if kunden_id is not None:
query = query.filter(Projekt.kunden_id == kunden_id)
return query.order_by(Projekt.projektname).all()
def get_projekt(projekt_id: int) -> Projekt: