Prior to updating queries to use query alias.

This commit is contained in:
lwark
2025-01-27 08:55:34 -06:00
parent 960fbdb85c
commit 73752cde87
10 changed files with 351 additions and 87 deletions

View File

@@ -6,9 +6,10 @@ from PyQt6.QtCore import QSortFilterProxyModel, Qt
from PyQt6.QtGui import QAction, QCursor
from PyQt6.QtWidgets import (
QLabel, QDialog,
QTableView, QWidget, QLineEdit, QGridLayout, QComboBox, QPushButton, QDialogButtonBox, QDateEdit, QMenu
QTableView, QWidget, QLineEdit, QGridLayout, QComboBox, QPushButton, QDialogButtonBox, QDateEdit, QMenu,
QDoubleSpinBox, QSpinBox, QCheckBox
)
from sqlalchemy import String, TIMESTAMP
from sqlalchemy import String, TIMESTAMP, FLOAT, INTEGER, JSON, BLOB
from sqlalchemy.orm import InstrumentedAttribute
from sqlalchemy.orm.collections import InstrumentedList
from sqlalchemy.orm.properties import ColumnProperty
@@ -28,10 +29,16 @@ class ManagerWindow(QDialog):
Initially this is a window to manage Organization Contacts, but hope to abstract it more later.
"""
def __init__(self, parent, object_type: Any, extras: List[str], **kwargs):
def __init__(self, parent, object_type: Any, extras: List[str], managers: set = set(), **kwargs):
super().__init__(parent)
self.object_type = self.original_type = object_type
self.instance = None
self.managers = managers
try:
self.managers.add(self.parent().instance)
except AttributeError:
pass
logger.debug(f"Managers: {managers}")
self.extras = extras
self.context = kwargs
self.layout = QGridLayout(self)
@@ -55,7 +62,7 @@ class ManagerWindow(QDialog):
self.options.setObjectName("options")
self.update_options()
self.setLayout(self.layout)
self.setWindowTitle(f"Manage {self.object_type.__name__}")
self.setWindowTitle(f"Manage {self.object_type.__name__} - Managers: {self.managers}")
def update_options(self) -> None:
"""
@@ -63,8 +70,15 @@ class ManagerWindow(QDialog):
"""
if self.sub_class:
self.object_type = getattr(db, self.sub_class.currentText())
options = [item.name for item in self.object_type.query()]
logger.debug(f"self.instance: {self.instance}")
logger.debug(f"From update options, managers: {self.managers}")
try:
query_kwargs = {self.parent().instance.query_alias: self.parent().instance}
except AttributeError as e:
logger.debug(f"Couldn't set query kwargs due to: {e}")
query_kwargs = {}
logger.debug(f"Query kwargs: {query_kwargs}")
options = [item.name for item in self.object_type.query(**query_kwargs)]
logger.debug(f"self.object_type: {self.object_type}")
if self.instance:
options.insert(0, options.pop(options.index(self.instance.name)))
self.options.clear()
@@ -92,21 +106,24 @@ class ManagerWindow(QDialog):
for item in deletes:
item.setParent(None)
# NOTE: Find the instance this manager will update
self.instance = self.object_type.query(name=self.options.currentText())
fields = {k: v for k, v in self.object_type.__dict__.items() if
isinstance(v, InstrumentedAttribute) and k != "id"}
logger.debug(f"Querying with {self.options.currentText()}")
self.instance = self.object_type.query(name=self.options.currentText(), limit=1)
logger.debug(f"Instance: {self.instance}")
fields = {k: v for k, v in self.instance.omnigui_dict.items() if
isinstance(v['class_attr'], InstrumentedAttribute) and k != "id"}
# logger.debug(f"Instance fields: {fields}")
for key, field in fields.items():
match field.property:
match field['class_attr'].property:
# NOTE: ColumnProperties will be directly edited.
case ColumnProperty():
# NOTE: field.property.expression.type gives db column type eg. STRING or TIMESTAMP
widget = EditProperty(self, key=key, column_type=field.property.expression.type,
widget = EditProperty(self, key=key, column_type=field,
value=getattr(self.instance, key))
# NOTE: RelationshipDeclareds will be given a list of existing related objects.
case _RelationshipDeclared():
if key != "submissions":
# NOTE: field.comparator.entity.class_ gives the relationship class
widget = EditRelationship(self, key=key, entity=field.comparator.entity.class_,
widget = EditRelationship(self, key=key, entity=field['class_attr'].comparator.entity.class_,
value=getattr(self.instance, key))
else:
continue
@@ -132,7 +149,7 @@ class ManagerWindow(QDialog):
return self.instance
def add_new(self):
dlg = AddEdit(parent=self, instance=self.object_type(), manager=self.object_type.__name__.lower())
dlg = AddEdit(parent=self, instance=self.object_type(), managers=self.managers)
if dlg.exec():
new_pyd = dlg.parse_form()
new_instance = new_pyd.to_sql()
@@ -148,13 +165,33 @@ class EditProperty(QWidget):
self.label = QLabel(key.title().replace("_", " "))
self.layout = QGridLayout()
self.layout.addWidget(self.label, 0, 0, 1, 1)
match column_type:
logger.debug(f"Column type: {column_type}")
match column_type['class_attr'].property.expression.type:
case String():
self.widget = QLineEdit(self)
self.widget.setText(value)
case INTEGER():
if isinstance(column_type['instance_attr'], bool):
self.widget = QCheckBox()
self.widget.setChecked(value)
else:
if value is None:
value = 1
self.widget = QSpinBox()
self.widget.setValue(value)
case FLOAT():
if not value:
value = 1.0
self.widget = QDoubleSpinBox()
self.widget.setMaximum(999.99)
self.widget.setValue(value)
case TIMESTAMP():
self.widget = QDateEdit(self)
self.widget.setDate(value)
case JSON():
self.widget = QLabel("JSON Under construction")
case BLOB():
self.widget = QLabel("BLOB Under construction")
case _:
self.widget = None
self.layout.addWidget(self.widget, 0, 1, 1, 3)
@@ -175,7 +212,7 @@ class EditRelationship(QWidget):
def __init__(self, parent, key: str, entity: Any, value):
super().__init__(parent)
self.entity = entity
self.entity = entity #: The class of interest
self.data = value
self.label = QLabel(key.title().replace("_", " "))
self.setObjectName(key)
@@ -184,10 +221,11 @@ class EditRelationship(QWidget):
self.add_button.clicked.connect(self.add_new)
self.existing_button = QPushButton("Add Existing")
self.existing_button.clicked.connect(self.add_existing)
self.existing_button.setEnabled(self.entity.level == 1)
self.layout = QGridLayout()
self.layout.addWidget(self.label, 0, 0, 1, 5)
self.layout.addWidget(self.table, 1, 0, 1, 8)
self.layout.addWidget(self.add_button, 0, 6, 1, 1, alignment=Qt.AlignmentFlag.AlignRight)
self.layout.addWidget(self.add_button, 0, 6, 1, 1, alignment=Qt.AlignmentFlag.AlignRight)
self.layout.addWidget(self.existing_button, 0, 7, 1, 1, alignment=Qt.AlignmentFlag.AlignRight)
self.setLayout(self.layout)
self.set_data()
@@ -205,17 +243,30 @@ class EditRelationship(QWidget):
self.add_edit(instance=object)
def add_new(self, instance: Any = None):
# NOTE: if an existing instance is not being edited, create a new instance
if not instance:
instance = self.entity()
dlg = AddEdit(self, instance=instance, manager=self.parent().object_type.__name__.lower())
# if self.parent().object_type.level == 2:
managers = self.parent().managers
# else:
# managers = self.parent().managers + [self.parent().instance]
match instance.level:
case 1:
dlg = AddEdit(self.parent(), instance=instance, managers=managers)
case 2:
dlg = ManagerWindow(self.parent(), object_type=instance.__class__, extras=[], managers=managers)
case _:
return
if dlg.exec():
new_instance = dlg.parse_form()
new_instance, result = new_instance.to_sql()
new_instance = new_instance.to_sql()
logger.debug(f"New instance: {new_instance}")
addition = getattr(self.parent().instance, self.objectName())
if isinstance(addition, InstrumentedList):
addition.append(new_instance)
self.parent().instance.save()
logger.debug(f"Addition: {addition}")
# NOTE: Saving currently disabled
# if isinstance(addition, InstrumentedList):
# addition.append(new_instance)
# self.parent().instance.save()
self.parent().update_data()
def add_existing(self):
@@ -223,11 +274,15 @@ class EditRelationship(QWidget):
if dlg.exec():
rows = dlg.return_selected_rows()
for row in rows:
logger.debug(f"Querying with {row}")
instance = self.entity.query(**row)
logger.debug(f"Queried instance: {instance}")
addition = getattr(self.parent().instance, self.objectName())
if isinstance(addition, InstrumentedList):
addition.append(instance)
self.parent().instance.save()
logger.debug(f"Addition: {addition}")
# NOTE: Saving currently disabled
# if isinstance(addition, InstrumentedList):
# addition.append(instance)
# self.parent().instance.save()
self.parent().update_data()
def set_data(self) -> None:
@@ -235,7 +290,11 @@ class EditRelationship(QWidget):
sets data in model
"""
# logger.debug(self.data)
self.data = DataFrame.from_records([item.omnigui_dict for item in self.data])
if not isinstance(self.data, list):
self.data = [self.data]
records = [{k: v['instance_attr'] for k, v in item.omnigui_dict.items()} for item in self.data]
# logger.debug(f"Records: {records}")
self.data = DataFrame.from_records(records)
try:
self.columns_of_interest = [dict(name=item, column=self.data.columns.get_loc(item)) for item in self.extras]
except (KeyError, AttributeError):
@@ -261,8 +320,13 @@ class EditRelationship(QWidget):
event (_type_): the item of interest
"""
id = self.table.selectionModel().currentIndex()
id = int(id.sibling(id.row(), 0).data())
object = self.entity.query(id=id)
# NOTE: the overly complicated {column_name: row_value} dictionary construction
row_data = {self.data.columns[column]: self.table.model().index(id.row(), column).data() for column in
range(self.table.model().columnCount())}
object = self.entity.query(**row_data)
if isinstance(object, list):
object = object[0]
logger.debug(object)
self.menu = QMenu(self)
action = QAction(f"Remove {object.name}", self)
action.triggered.connect(lambda: self.remove_item(object=object))