exclude for auto-update fields

This commit is contained in:
2026-05-26 09:52:57 +02:00
parent d468fe9058
commit 078cfee7ed
3 changed files with 67 additions and 18 deletions

View File

@@ -183,8 +183,8 @@ class FlatBaseModel(BaseModel):
# 1. Die aktuelle Ebene dieses Dictionaries ent-flachen # 1. Die aktuelle Ebene dieses Dictionaries ent-flachen
unflattened_level = {} unflattened_level = {}
for key, value in data.items(): for key, value in data.items():
if "__" in key: if COLUMN_SEP in key:
parts = key.split("__") parts = key.split(COLUMN_SEP)
aktuell = unflattened_level aktuell = unflattened_level
for part in parts[:-1]: for part in parts[:-1]:
if part not in aktuell or not isinstance(aktuell[part], dict): if part not in aktuell or not isinstance(aktuell[part], dict):
@@ -219,14 +219,14 @@ class FlatBaseModel(BaseModel):
return final_nested_data return final_nested_data
def to_db(self) -> dict[str, Any]: def to_db(self, *args, **kwargs) -> dict[str, Any]:
"""Ausgang für die DB: Flach, Listen sind JSON-Strings.""" """Ausgang für die DB: Flach, Listen sind JSON-Strings."""
nested = super().model_dump() nested = super().model_dump(*args, **kwargs)
return self.__flatten_dict(nested, serialize_lists=True) return self.__flatten_dict(nested, serialize_lists=True)
def to_gui(self) -> dict[str, Any]: def to_gui(self, *args, **kwargs) -> dict[str, Any]:
"""Ausgang für die GUI: Flach, aber Listen bleiben Python-Listen.""" """Ausgang für die GUI: Flach, aber Listen bleiben Python-Listen."""
nested = super().model_dump() nested = super().model_dump(*args, **kwargs)
return self.__flatten_dict(nested, serialize_lists=False) return self.__flatten_dict(nested, serialize_lists=False)
@classmethod @classmethod
@@ -236,7 +236,7 @@ class FlatBaseModel(BaseModel):
"""Rekursiver Helfer zum Abflachen von Strukturen.""" """Rekursiver Helfer zum Abflachen von Strukturen."""
items = [] items = []
for k, v in nested_dict.items(): for k, v in nested_dict.items():
new_key = f"{parent_key}__{k}" if parent_key else k new_key = f"{parent_key}{COLUMN_SEP}{k}" if parent_key else k
if isinstance(v, dict): if isinstance(v, dict):
items.extend(cls.__flatten_dict(v, new_key, serialize_lists).items()) items.extend(cls.__flatten_dict(v, new_key, serialize_lists).items())
@@ -901,11 +901,18 @@ def update_sub_forms(
del widget_registry[key] del widget_registry[key]
@dc.dataclass(slots=True)
class FormData:
data: dict[str, Any]
ignored_keys: Iterable[str]
def get_form_data( def get_form_data(
widget_registry: WidgetRegistry, widget_registry: WidgetRegistry,
filter_keys: Container[str] = tuple(), filter_keys: Container[str] = tuple(),
) -> dict[str, Any]: ) -> dict[str, Any]:
raw_data = {} raw_data: dict[str, Any] = {}
ignored_keys: list[str] = []
for key, registry_entry in widget_registry.items(): for key, registry_entry in widget_registry.items():
value: Any | None = None value: Any | None = None
@@ -917,6 +924,7 @@ def get_form_data(
widget = registry_entry["widget"] widget = registry_entry["widget"]
form_field = registry_entry["form_field"] form_field = registry_entry["form_field"]
if form_field.ignore_get_data: if form_field.ignore_get_data:
ignored_keys.append(key)
continue continue
if isinstance(widget, QLineEdit): if isinstance(widget, QLineEdit):
@@ -1672,6 +1680,7 @@ class AutoForm(QWidget):
self, self,
form_fields: Sequence[FormField], form_fields: Sequence[FormField],
add_buttons: bool = True, add_buttons: bool = True,
ignored_keys: Iterable[str] = tuple(),
) -> None: ) -> None:
super().__init__() super().__init__()
self.setStyleSheet(""" self.setStyleSheet("""
@@ -1761,6 +1770,7 @@ class AutoForm(QWidget):
self.reset_btn.clicked.connect(self.reset_form) self.reset_btn.clicked.connect(self.reset_form)
self.layout_btn.addWidget(self.reset_btn) self.layout_btn.addWidget(self.reset_btn)
self.ignored_keys = ignored_keys
# test button # test button
# self.main_layout.addSpacing(10) # self.main_layout.addSpacing(10)
# self.main_layout.addWidget(self.test_button) # self.main_layout.addWidget(self.test_button)
@@ -1819,7 +1829,7 @@ class AutoForm(QWidget):
validated_data = Grunderfassung_Unternehmen(**form_data) validated_data = Grunderfassung_Unternehmen(**form_data)
# # TODO remove # # TODO remove
# validated_data.Metadaten_erstellung = datetime.datetime.now() # validated_data.Metadaten_erstellung = datetime.datetime.now()
logger.debug("%s", pformat(validated_data.model_dump())) # logger.debug("%s", pformat(validated_data.model_dump()))
except ValidationError as e: except ValidationError as e:
# catch errors and show them in GUI # catch errors and show them in GUI
fehler_texte = [] fehler_texte = []
@@ -1848,9 +1858,17 @@ class AutoForm(QWidget):
save_pydantic_model_dict_db(validated_data) save_pydantic_model_dict_db(validated_data)
# TODO save data to database # TODO save data to database
logger.info( logger.info(
"\n\n>>>>>>>>>>>>> The following data muste be saved in the database:\n%s", "\n\n>>>>>>>>>>>>> Form data without 'exlude':\n%s",
pformat(validated_data.to_db()), pformat(validated_data.to_db()),
) )
logger.info(
(
"\n\n>>>>>>>>>>>>> Form data with 'exlude' "
"(must be saved in the database):\n%s"
),
pformat(validated_data.to_db(exclude=self.ignored_keys)),
)
logger_get_data.info("Data saved successfully") logger_get_data.info("Data saved successfully")
finally: finally:
# always re-enable save, even if error occurred # always re-enable save, even if error occurred
@@ -1985,7 +2003,7 @@ class DynamicListWidget(QWidget):
return errors return errors
def get_form_data(self): def get_form_data(self) -> list[dict[str, Any]]:
# raw_data = get_form_data(self.widget_registry) # raw_data = get_form_data(self.widget_registry)
# form_data = get_form_data(self.widget_registry) # form_data = get_form_data(self.widget_registry)
# logger_get_data.debug( # logger_get_data.debug(
@@ -1997,6 +2015,10 @@ class DynamicListWidget(QWidget):
# pprint_registry(sub_form.registry) # pprint_registry(sub_form.registry)
form_data = [get_form_data(sub.registry) for sub in self.sub_forms] form_data = [get_form_data(sub.registry) for sub in self.sub_forms]
# ignored_keys: list[str] = []
# for d in form_data:
# ignored_keys.extend(d.ignored_keys)
# data = [d.data for d in form_data]
logger_get_data.debug("##################") logger_get_data.debug("##################")
logger_get_data.debug("Form data:\n%s", pformat(form_data)) logger_get_data.debug("Form data:\n%s", pformat(form_data))
@@ -2168,7 +2190,7 @@ class DynamicDropdownWidget(QWidget):
return errors return errors
def get_form_data(self): def get_form_data(self) -> dict[str, Any]:
# raw_data = get_form_data(self.widget_registry) # raw_data = get_form_data(self.widget_registry)
form_data = get_form_data(self.widget_registry) form_data = get_form_data(self.widget_registry)
@@ -3357,7 +3379,15 @@ class SearchFormPage(QWidget):
title.setStyleSheet("font-size: 14px; font-style: italic;") # font-weight: bold; title.setStyleSheet("font-size: 14px; font-style: italic;") # font-weight: bold;
container_layout.addWidget(title) container_layout.addWidget(title)
# container_layout.addWidget(MyFormPart(FORM_FIELD_DEF, "Test-Gruppe")) # container_layout.addWidget(MyFormPart(FORM_FIELD_DEF, "Test-Gruppe"))
container_layout.addWidget(AutoForm(FORM_FIELDS)) container_layout.addWidget(
AutoForm(
FORM_FIELDS,
ignored_keys=(
"Metadaten_erstellung",
"Metadaten_aktualisierung",
),
)
)
container_layout.addSpacing(30) container_layout.addSpacing(30)

6
src/wce_crm/constants.py Normal file
View File

@@ -0,0 +1,6 @@
from __future__ import annotations
from pathlib import Path
from typing import Final
LIB_PATH: Final[Path] = Path(__file__).parent

View File

@@ -1,8 +1,8 @@
from __future__ import annotations from __future__ import annotations
import datetime
import os import os
import re import re
from datetime import datetime
from pathlib import Path from pathlib import Path
import polars as pl import polars as pl
@@ -26,7 +26,7 @@ class SafeDateTime(TypeDecorator):
clean_value = re.sub(r"[a-zA-Z]+$", "", value).replace(",", ".") clean_value = re.sub(r"[a-zA-Z]+$", "", value).replace(",", ".")
try: try:
return datetime.fromisoformat(clean_value) return datetime.datetime.fromisoformat(clean_value)
except ValueError: except ValueError:
# Fallback if it's still weird # Fallback if it's still weird
return None return None
@@ -302,6 +302,20 @@ grunderfassung_unternehmen: sql.Table = Table(
"grunderfassung_unternehmen", "grunderfassung_unternehmen",
md_main, md_main,
Column("erfassung_id", sql.Integer, nullable=False, unique=True, autoincrement=True), Column("erfassung_id", sql.Integer, nullable=False, unique=True, autoincrement=True),
Column(
"Metadaten_erstellung",
sql.DateTime(timezone=True),
nullable=True,
default=lambda: datetime.datetime.now(datetime.UTC),
),
Column(
"Metadaten_aktualisierung",
sql.DateTime(timezone=True),
nullable=True,
default=lambda: datetime.datetime.now(datetime.UTC),
onupdate=lambda: datetime.datetime.now(datetime.UTC),
),
Column("Metadaten_nutzer", sql.String(20), nullable=True),
Column("Arbeitserfahrung", sql.Text, nullable=True), Column("Arbeitserfahrung", sql.Text, nullable=True),
Column("Grunderfassung_fallnummer", sql.Text, nullable=True), Column("Grunderfassung_fallnummer", sql.Text, nullable=True),
Column("Grunderfassung_notiz", sql.Text, nullable=True), Column("Grunderfassung_notiz", sql.Text, nullable=True),
@@ -316,9 +330,8 @@ grunderfassung_unternehmen: sql.Table = Table(
Column("Kontaktperson__KP_name_partner", sql.Text, nullable=True), Column("Kontaktperson__KP_name_partner", sql.Text, nullable=True),
Column("Kontaktperson__KP_titel", sql.Text, nullable=True), Column("Kontaktperson__KP_titel", sql.Text, nullable=True),
Column("Kontaktperson__KP_vorname", sql.Text, nullable=True), Column("Kontaktperson__KP_vorname", sql.Text, nullable=True),
Column("Metadaten_aktualisierung", sql.Text, nullable=True), # Column("Metadaten_aktualisierung", sql.Text, nullable=True),
Column("Metadaten_erstellung", sql.Text, nullable=True), # Column("Metadaten_erstellung", sql.Text, nullable=True),
Column("Metadaten_nutzer", sql.String(20), nullable=True),
Column("Partnersuche__kanal_aufmerksamkeit", sql.Text, nullable=True), Column("Partnersuche__kanal_aufmerksamkeit", sql.Text, nullable=True),
Column("Partnersuche__person_suche", sql.Text, nullable=True), Column("Partnersuche__person_suche", sql.Text, nullable=True),
Column("Partnersuche__un_suche", sql.Text, nullable=True), Column("Partnersuche__un_suche", sql.Text, nullable=True),