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:
1 parent
e9a2f48ede
commit
93827dde0f
15 files changed
+189
-141
No files matched your search
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -80,8 +80,9 @@ def kunde_delete():
|
||||
@app.get("/xhr/kontakt/list")
|
||||
@authorisation_required([MITARBEITER, KUNDEN_MANAGER])
|
||||
def kontakt_list():
|
||||
"""Liefert alle Kontakte als Liste."""
|
||||
result = [k.to_dict() for k in kontakte.get_kontakte()]
|
||||
"""Liefert Kontakte als Liste. Optional nach kunden_id gefiltert."""
|
||||
kunden_id = request.args.get("kunden_id", type=int)
|
||||
result = [k.to_dict() for k in kontakte.get_kontakte(kunden_id)]
|
||||
return jsonify(result), 200
|
||||
|
||||
|
||||
@@ -125,8 +126,9 @@ def kontakt_delete():
|
||||
@app.get("/xhr/projekt/list")
|
||||
@authorisation_required([MITARBEITER, KUNDEN_MANAGER])
|
||||
def projekt_list():
|
||||
"""Liefert alle Projekte als Liste."""
|
||||
result = [p.to_dict() for p in projekte.get_projekte()]
|
||||
"""Liefert Projekte als Liste. Optional nach kunden_id gefiltert."""
|
||||
kunden_id = request.args.get("kunden_id", type=int)
|
||||
result = [p.to_dict() for p in projekte.get_projekte(kunden_id)]
|
||||
return jsonify(result), 200
|
||||
|
||||
|
||||
@@ -170,8 +172,9 @@ def projekt_delete():
|
||||
@app.get("/xhr/kontaktadresse/list")
|
||||
@authorisation_required([MITARBEITER, KUNDEN_MANAGER])
|
||||
def kontaktadresse_list():
|
||||
"""Liefert alle Kontaktadressen als Liste."""
|
||||
result = [k.to_dict() for k in kontaktadressen.get_kontaktadressen()]
|
||||
"""Liefert Kontaktadressen als Liste. Optional nach projekt_id gefiltert."""
|
||||
projekt_id = request.args.get("projekt_id", type=int)
|
||||
result = [k.to_dict() for k in kontaktadressen.get_kontaktadressen(projekt_id)]
|
||||
return jsonify(result), 200
|
||||
|
||||
|
||||
@@ -215,8 +218,9 @@ def kontaktadresse_delete():
|
||||
@app.get("/xhr/calllog/list")
|
||||
@authorisation_required([MITARBEITER, KUNDEN_MANAGER])
|
||||
def calllog_list():
|
||||
"""Liefert alle Gesprächsnotizen als Liste."""
|
||||
result = [l.to_dict() for l in call_logs.get_call_logs()]
|
||||
"""Liefert Gesprächsnotizen als Liste. Optional nach projekt_id gefiltert."""
|
||||
projekt_id = request.args.get("projekt_id", type=int)
|
||||
result = [l.to_dict() for l in call_logs.get_call_logs(projekt_id)]
|
||||
return jsonify(result), 200
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user