add export to json
This commit is contained in:
+98
-20
@@ -1,3 +1,7 @@
|
|||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import mariadb
|
import mariadb
|
||||||
from sqlalchemy import create_engine, select, text, MetaData, join
|
from sqlalchemy import create_engine, select, text, MetaData, join
|
||||||
from sqlalchemy.orm import DeclarativeBase, relationship, sessionmaker
|
from sqlalchemy.orm import DeclarativeBase, relationship, sessionmaker
|
||||||
@@ -30,35 +34,67 @@ class KontorDB:
|
|||||||
__session__ = sessionmaker(bind=engine)
|
__session__ = sessionmaker(bind=engine)
|
||||||
self.session = __session__()
|
self.session = __session__()
|
||||||
|
|
||||||
def get_table_id(self, table_name):
|
|
||||||
result = self.session.execute(select(MetaDataTable.id).where(MetaDataTable.table_name == table_name)).scalar()
|
|
||||||
return result
|
|
||||||
|
|
||||||
def get_table_names(self) -> list:
|
def get_table_names(self) -> list:
|
||||||
tables = self.session.query(MetaDataTable).all()
|
tables = self.session.query(MetaDataTable).all()
|
||||||
result = [table.table_name for table in tables]
|
result = [table.table_name for table in tables]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_column_meta_data(self, table_id: str, table_name: str) -> dict:
|
def get_column_meta_data(self, table_name: str, view_only=True) -> dict:
|
||||||
meta_data = {}
|
meta_data = {}
|
||||||
order = 0
|
order = 0
|
||||||
for (_, column) in self.session.query(MetaDataTable, MetaDataColumn).filter(MetaDataTable.id == MetaDataColumn.table_id).filter(MetaDataTable.table_name == table_name).filter(MetaDataColumn.is_shown == 1).all():
|
if view_only:
|
||||||
meta_data[order] = {'column': column.column_name, 'label': column.column_label, 'order': column.column_order, 'ref_column': column.ref_column}
|
for (_, column) in (self.session.query(MetaDataTable, MetaDataColumn).
|
||||||
order += 1
|
filter(MetaDataTable.id == MetaDataColumn.table_id).
|
||||||
|
filter(MetaDataTable.table_name == table_name).
|
||||||
|
filter(MetaDataColumn.is_shown == 1).all()):
|
||||||
|
meta_data[order] = {'column': column.column_name, 'label': column.column_label,
|
||||||
|
'order': column.column_order, 'ref_column': column.ref_column}
|
||||||
|
order += 1
|
||||||
|
else:
|
||||||
|
for (_, column) in (self.session.query(MetaDataTable, MetaDataColumn).
|
||||||
|
filter(MetaDataTable.id == MetaDataColumn.table_id).
|
||||||
|
filter(MetaDataTable.table_name == table_name).all()):
|
||||||
|
meta_data[order] = {
|
||||||
|
'column': column.column_name,
|
||||||
|
'order': column.column_order,
|
||||||
|
'ref_column': column.ref_column
|
||||||
|
}
|
||||||
|
order += 1
|
||||||
return meta_data
|
return meta_data
|
||||||
|
|
||||||
def get_filters(self, table_id):
|
def get_filters(self, table_name):
|
||||||
cursor = self.db_conn.cursor()
|
_filter_map = {}
|
||||||
filters = {}
|
for (_, column) in (self.session.query(MetaDataTable, MetaDataColumn).
|
||||||
cursor.execute(
|
filter(MetaDataTable.id == MetaDataColumn.table_id).
|
||||||
"SELECT column_name, filter_label from meta_data_column WHERE table_id=? AND show_filter is true",
|
filter(MetaDataTable.table_name == table_name).
|
||||||
(table_id,))
|
filter(MetaDataColumn.show_filter == 1).all()):
|
||||||
rows = cursor.fetchall()
|
_filter_map[column.column_name] = {'label': column.filter_label, 'widget': None}
|
||||||
for row in rows:
|
print(f"retrieved {len(_filter_map)} filters: {_filter_map}")
|
||||||
filters[row[0]] = {'label': row[1], 'widget': None}
|
return _filter_map
|
||||||
cursor.close()
|
|
||||||
# print(f"retrieved {len(rows)} filters: {filters}")
|
def data(self, table, columns: dict, filters) -> list:
|
||||||
return filters
|
data = []
|
||||||
|
entries = []
|
||||||
|
if len(filters) == 0:
|
||||||
|
entries = self.session.query(table).all()
|
||||||
|
else:
|
||||||
|
entries = self.session.query(table).filter_by(**filters)
|
||||||
|
for entry in entries:
|
||||||
|
row = []
|
||||||
|
for order in columns.keys():
|
||||||
|
column_name = columns[order]['column']
|
||||||
|
if str(column_name).endswith("_id"):
|
||||||
|
ref_table = column_name[:-3]
|
||||||
|
# print(f"{ref_table=}")
|
||||||
|
ref = getattr(entry, ref_table)
|
||||||
|
value = getattr(ref, "name")
|
||||||
|
# print(f"{value=}")
|
||||||
|
row.append(value)
|
||||||
|
else:
|
||||||
|
row.append(getattr(entry, column_name))
|
||||||
|
# print(repr(row))
|
||||||
|
data.append(row)
|
||||||
|
return data
|
||||||
|
|
||||||
def get_data(self, table_name: str, columns: dict, where_clause: str) -> list:
|
def get_data(self, table_name: str, columns: dict, where_clause: str) -> list:
|
||||||
data = []
|
data = []
|
||||||
@@ -103,3 +139,45 @@ class KontorDB:
|
|||||||
statement = f"SELECT {columns} FROM {table} {where_clause}"
|
statement = f"SELECT {columns} FROM {table} {where_clause}"
|
||||||
print(f"{statement=}")
|
print(f"{statement=}")
|
||||||
return statement
|
return statement
|
||||||
|
|
||||||
|
def export_db(self, export_type: str, export_file_name: str, export_table_list: list):
|
||||||
|
print(f"export DB to {export_file_name} as {export_type}")
|
||||||
|
db = {}
|
||||||
|
for table in export_table_list:
|
||||||
|
columns = self.get_column_meta_data(table, view_only=False)
|
||||||
|
model = Base.model_lookup_by_table_name(table)
|
||||||
|
rows = self.session.query(model).all()
|
||||||
|
entries = []
|
||||||
|
print(f"found {len(rows)} entries")
|
||||||
|
print(f"found {len(columns)} columns")
|
||||||
|
for row in rows:
|
||||||
|
print(row)
|
||||||
|
entry = {}
|
||||||
|
for order in columns:
|
||||||
|
print(columns[order])
|
||||||
|
column_name = columns[order]['column']
|
||||||
|
print(f"get value {column_name} from {row} of table {table}")
|
||||||
|
try:
|
||||||
|
value = getattr(row, column_name)
|
||||||
|
if isinstance(value, datetime):
|
||||||
|
entry[column_name] = str(value)
|
||||||
|
else:
|
||||||
|
entry[column_name] = value
|
||||||
|
except AttributeError as error:
|
||||||
|
print("could not get value")
|
||||||
|
entries.append(entry)
|
||||||
|
db[table] = entries
|
||||||
|
export_file = Path(export_file_name)
|
||||||
|
match export_type:
|
||||||
|
case "JSON":
|
||||||
|
json_dump = json.dumps(db, indent=4)
|
||||||
|
with open(export_file_name, "w") as dump_file:
|
||||||
|
dump_file.write(json_dump)
|
||||||
|
case "YAML":
|
||||||
|
export_file = Path(export_file_name)
|
||||||
|
case "SQLite":
|
||||||
|
export_file = Path(export_file_name)
|
||||||
|
case _:
|
||||||
|
print("unknown export type")
|
||||||
|
if export_file.exists():
|
||||||
|
print(f"{export_file} exists")
|
||||||
|
|||||||
+16
-3
@@ -1,7 +1,20 @@
|
|||||||
from sqlalchemy import Column, String, DateTime, Integer
|
from sqlalchemy import Column, String, DateTime, Integer
|
||||||
from sqlalchemy.orm import DeclarativeBase, relationship, sessionmaker
|
from sqlalchemy.orm import DeclarativeBase, relationship, sessionmaker, declarative_base
|
||||||
|
|
||||||
|
|
||||||
class Base(DeclarativeBase):
|
# class Base(DeclarativeBase):
|
||||||
pass
|
# pass
|
||||||
|
|
||||||
|
class BaseModel:
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def model_lookup_by_table_name(cls, table_name):
|
||||||
|
registry_instance = getattr(cls, "registry")
|
||||||
|
for mapper_ in registry_instance.mappers:
|
||||||
|
model = mapper_.class_
|
||||||
|
model_class_name = model.__tablename__
|
||||||
|
if model_class_name == table_name:
|
||||||
|
return model
|
||||||
|
|
||||||
|
|
||||||
|
Base = declarative_base(cls=BaseModel)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String
|
from sqlalchemy import Column, DateTime, ForeignKey, Integer, String
|
||||||
from sqlalchemy.dialects.mysql import BIT
|
from sqlalchemy.dialects.mysql import BIT
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ class Artist(Base):
|
|||||||
comic_works = relationship("ComicWork")
|
comic_works = relationship("ComicWork")
|
||||||
|
|
||||||
|
|
||||||
class Worktype(Base):
|
class WorkType(Base):
|
||||||
__tablename__ = "worktype"
|
__tablename__ = "worktype"
|
||||||
id = Column(String, primary_key=True)
|
id = Column(String, primary_key=True)
|
||||||
created_date = Column(DateTime)
|
created_date = Column(DateTime)
|
||||||
@@ -126,5 +126,5 @@ class ComicWork(Base):
|
|||||||
comic = relationship("Comic", back_populates="comic_works")
|
comic = relationship("Comic", back_populates="comic_works")
|
||||||
artist_id = Column(String, ForeignKey("artist.id"), nullable=False)
|
artist_id = Column(String, ForeignKey("artist.id"), nullable=False)
|
||||||
artist = relationship("Artist", back_populates="comic_works")
|
artist = relationship("Artist", back_populates="comic_works")
|
||||||
worktype_id = Column(String, ForeignKey("worktype.id"), nullable=False)
|
work_type_id = Column(String, ForeignKey("worktype.id"), nullable=False)
|
||||||
worktype = relationship("Worktype", back_populates="comic_works")
|
work_type = relationship("WorkType", back_populates="comic_works")
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from PyQt5.QtCore import QAbstractTableModel
|
from PySide6.QtCore import QModelIndex, QAbstractTableModel
|
||||||
from PySide6.QtCore import QModelIndex
|
|
||||||
from PySide6.QtGui import Qt
|
from PySide6.QtGui import Qt
|
||||||
|
|
||||||
from gui.data_view import DataViewMeta
|
from gui.data_view import DataViewMeta
|
||||||
@@ -14,19 +13,19 @@ class DataViewModel(QAbstractTableModel):
|
|||||||
self._config = None
|
self._config = None
|
||||||
self._data = List[DataViewMeta]
|
self._data = List[DataViewMeta]
|
||||||
|
|
||||||
def rowCount(self, parent = QModelIndex()):
|
def rowCount(self, parent=QModelIndex()):
|
||||||
return len(self._data)
|
return len(self._data)
|
||||||
|
|
||||||
def columnCount(self, parent = QModelIndex()):
|
def columnCount(self, parent=QModelIndex()):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def headerData(self, section, orientation, role = Qt.ItemDataRole.DisplayRole):
|
def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def data(self, index, role = Qt.ItemDataRole.DisplayRole):
|
def data(self, index, role=Qt.ItemDataRole.DisplayRole):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def setData(self, index, value, role = Qt.ItemDataRole.EditRole):
|
def setData(self, index, value, role=Qt.ItemDataRole.EditRole):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def flags(self, index):
|
def flags(self, index):
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from PySide6.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QHBoxLayout, QPushButton, QFileDialog, \
|
from PySide6.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QHBoxLayout, QPushButton, QFileDialog, \
|
||||||
QGroupBox, QCheckBox, QComboBox
|
QCheckBox, QComboBox
|
||||||
|
|
||||||
|
|
||||||
class ExportKontorDialog(QDialog):
|
class ExportKontorDialog(QDialog):
|
||||||
@@ -10,7 +10,7 @@ class ExportKontorDialog(QDialog):
|
|||||||
|
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.kontor_db = kontor_db
|
self.kontor_db = kontor_db
|
||||||
self.file_name = None
|
self.file_name = "data.json"
|
||||||
self.tables = []
|
self.tables = []
|
||||||
self._table_options = {}
|
self._table_options = {}
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ class MainWindow(QMainWindow):
|
|||||||
parent_layout = QVBoxLayout()
|
parent_layout = QVBoxLayout()
|
||||||
self.central_widget.setLayout(parent_layout)
|
self.central_widget.setLayout(parent_layout)
|
||||||
self.tabs = QTabWidget()
|
self.tabs = QTabWidget()
|
||||||
self.tabs.addTab(self.generate_data_tab("comic"), "Comics")
|
self.tabs.addTab(self.generate_data_tab("comic", Comic), "Comics")
|
||||||
self.tabs.addTab(self.generate_data_tab("media_file"), "MediaFile")
|
self.tabs.addTab(self.generate_data_tab("media_file", MediaFile), "MediaFile")
|
||||||
self.tabs.currentChanged.connect(self._tab_changed)
|
self.tabs.currentChanged.connect(self._tab_changed)
|
||||||
#label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
#label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
parent_layout.addWidget(self.tabs)
|
parent_layout.addWidget(self.tabs)
|
||||||
@@ -112,6 +112,7 @@ class MainWindow(QMainWindow):
|
|||||||
print(export_dlg.get_tables_to_export())
|
print(export_dlg.get_tables_to_export())
|
||||||
print(f"export DB to {export_dlg.file_name}")
|
print(f"export DB to {export_dlg.file_name}")
|
||||||
self.statusBar.showMessage(f"export DB to {export_dlg.file_name}", 3000)
|
self.statusBar.showMessage(f"export DB to {export_dlg.file_name}", 3000)
|
||||||
|
self.kontor_db.export_db(export_dlg.current_export_type, export_dlg.file_name, export_dlg.get_tables_to_export())
|
||||||
else:
|
else:
|
||||||
self.statusBar.showMessage("Export cancelled", 3000)
|
self.statusBar.showMessage("Export cancelled", 3000)
|
||||||
|
|
||||||
@@ -121,9 +122,9 @@ class MainWindow(QMainWindow):
|
|||||||
def _tab_changed(self, tab_index):
|
def _tab_changed(self, tab_index):
|
||||||
self.data[tab_index].refresh()
|
self.data[tab_index].refresh()
|
||||||
|
|
||||||
def generate_data_tab(self, table_name):
|
def generate_data_tab(self, table_name, table):
|
||||||
data_tab = QWidget()
|
data_tab = QWidget()
|
||||||
table_config = KontorModelConfig(self.kontor_db, self, table_name)
|
table_config = KontorModelConfig(self.kontor_db, self, table_name, table)
|
||||||
model = KontorTableModel(table_config)
|
model = KontorTableModel(table_config)
|
||||||
layout = QVBoxLayout()
|
layout = QVBoxLayout()
|
||||||
self.data.append(model)
|
self.data.append(model)
|
||||||
|
|||||||
+18
-13
@@ -6,25 +6,18 @@ from database import KontorDB
|
|||||||
|
|
||||||
class KontorModelConfig:
|
class KontorModelConfig:
|
||||||
|
|
||||||
def __init__(self, kontor_db: KontorDB, main_window, table_name: str):
|
def __init__(self, kontor_db: KontorDB, main_window, table_name: str, table):
|
||||||
self.header = {}
|
self.header = {}
|
||||||
self.filter = {}
|
self.filter = {}
|
||||||
self.main_window = main_window
|
self.main_window = main_window
|
||||||
self._table = table_name
|
self._table_name = table_name
|
||||||
self._table_id = None
|
self._table = table
|
||||||
self.kontor_db = kontor_db
|
self.kontor_db = kontor_db
|
||||||
self.get_table_config()
|
self.get_table_config()
|
||||||
|
|
||||||
def get_table_id(self):
|
|
||||||
if self._table_id is not None:
|
|
||||||
return
|
|
||||||
self._table_id = self.kontor_db.get_table_id(self._table)
|
|
||||||
|
|
||||||
def get_table_config(self):
|
def get_table_config(self):
|
||||||
if self._table_id is None:
|
self.header = self.kontor_db.get_column_meta_data(self._table_name)
|
||||||
self.get_table_id()
|
self.filter = self.kontor_db.get_filters(self._table_name)
|
||||||
self.header = self.kontor_db.get_column_meta_data(self._table_id, self._table)
|
|
||||||
self.filter = self.kontor_db.get_filters(self._table_id)
|
|
||||||
|
|
||||||
def get_filter(self) -> str:
|
def get_filter(self) -> str:
|
||||||
filter_rule = ""
|
filter_rule = ""
|
||||||
@@ -41,8 +34,20 @@ class KontorModelConfig:
|
|||||||
# print(f"{filter_rule=}")
|
# print(f"{filter_rule=}")
|
||||||
return filter_rule
|
return filter_rule
|
||||||
|
|
||||||
|
def filters(self) -> dict:
|
||||||
|
_filters = {}
|
||||||
|
# print(self.filter["download"].isChecked())
|
||||||
|
for column, filter_info in self.filter.items():
|
||||||
|
# print(column, filter_info)
|
||||||
|
if filter_info['widget'].isChecked():
|
||||||
|
_filters[column] = True
|
||||||
|
# print(f"{filter_rule=}")
|
||||||
|
return _filters
|
||||||
|
|
||||||
def get_data(self) -> list:
|
def get_data(self) -> list:
|
||||||
data = self.kontor_db.get_data(self._table, self.header, self.get_filter())
|
# data = self.kontor_db.get_data(self._table_name, self.header, self.get_filter())
|
||||||
|
# data.clear()
|
||||||
|
data = self.kontor_db.data(self._table, self.header, self.filters())
|
||||||
# print(f"KontorModelConfig.get_data: {len(data)}")
|
# print(f"KontorModelConfig.get_data: {len(data)}")
|
||||||
# comics = self.kontor_db.session.query(Comic).all()
|
# comics = self.kontor_db.session.query(Comic).all()
|
||||||
# print(f'{len(comics)} Comics loaded')
|
# print(f'{len(comics)} Comics loaded')
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class KontorTableModel(QAbstractTableModel):
|
|||||||
else:
|
else:
|
||||||
return self._main_window.cross
|
return self._main_window.cross
|
||||||
if isinstance(value, int):
|
if isinstance(value, int):
|
||||||
print('{}:: {}: {}'.format(index, value, type(value)))
|
# print('{}:: {}: {}'.format(index, value, type(value)))
|
||||||
if value == 1:
|
if value == 1:
|
||||||
return self._main_window.tick
|
return self._main_window.tick
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user