From 5505a521ffee3d16462d656aa55310f19d42606c Mon Sep 17 00:00:00 2001 From: litoq Date: Mon, 14 Apr 2025 22:20:31 +0300 Subject: [PATCH] implemented neo4j example --- .env | 9 ++++++ README.md | 14 ++++++++- main.py | 82 +++++++++++++++++++++++++++++++++++++++++++++++++-- neo_form.png | Bin 0 -> 8102 bytes 4 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 .env create mode 100644 neo_form.png diff --git a/.env b/.env new file mode 100644 index 0000000..cddec1c --- /dev/null +++ b/.env @@ -0,0 +1,9 @@ +POSTGRES_USER = postgres +POSTGRES_DB = university +POSTGRES_PASS = pass +POSTGRES_HOST = localhost +POSTGRES_PORT = 5432 + +NEO_USER=neo4j +NEO_PASS=pass +NEO_HOST=neo4j://localhost:7687 \ No newline at end of file diff --git a/README.md b/README.md index 5de7007..5e42353 100644 --- a/README.md +++ b/README.md @@ -3,5 +3,17 @@ Используется: - PyQt5 - PostgresSQL (psycopg2) +- Neo4j -![form.png](form.png) \ No newline at end of file +Postgres: + +![form.png](form.png) + +Neo4j: + +![neo_form.png](neo_form.png) + +### Подключение к БД + +Для подключения к БД указать в .env необходимые данные. +Для выборки данных из Neo4j должен быть создан обучающий граф фильмов. \ No newline at end of file diff --git a/main.py b/main.py index 9c3a7e1..41f931f 100644 --- a/main.py +++ b/main.py @@ -1,9 +1,24 @@ import psycopg2 from psycopg2 import sql from psycopg2.errors import DuplicateDatabase -from PyQt5.QtWidgets import QApplication, QMainWindow, QGridLayout, QWidget, QTableWidget, QTableWidgetItem, QHeaderView +from neo4j import GraphDatabase +from PyQt5.QtWidgets import QApplication, QMainWindow, QGridLayout, QWidget, QTableWidget, QTableWidgetItem, \ + QHeaderView, QVBoxLayout, QLabel from PyQt5.QtCore import QSize, Qt +import os +from dotenv import load_dotenv +load_dotenv() + +NEO_USER = os.getenv('NEO_USER') +NEO_PASS = os.getenv('NEO_PASS') +NEO_HOST = os.getenv('NEO_HOST') + +POSTGRES_USER = os.getenv('POSTGRES_USER') +POSTGRES_DB = os.getenv('POSTGRES_DB') +POSTGRES_PASS = os.getenv('POSTGRES_PASS') +POSTGRES_HOST = os.getenv('POSTGRES_HOST') +POSTGRES_PORT = os.getenv('POSTGRES_PORT') def connect(config): """ Connect to the PostgreSQL database server """ @@ -97,7 +112,7 @@ class MainWindow(QMainWindow): QMainWindow.__init__(self) self.setMinimumSize(QSize(480, 80)) # Set sizes - self.setWindowTitle("DB example") # Set the window title + self.setWindowTitle("postgre") # Set the window title central_widget = QWidget(self) # Create a central widget self.setCentralWidget(central_widget) # Install the central widget @@ -136,6 +151,54 @@ class MainWindow(QMainWindow): self.table.setItem(row_number, 2, QTableWidgetItem(str(user[2]))) +class NeoWindow(QWidget): + def __init__(self, parent_window): + super().__init__() + + self.setWindowTitle("neo4j") + self.resize(300, 250) + + grid_layout = QGridLayout(self) # Create QGridLayout + self.setLayout(grid_layout) # Set this layout in central widget + + self.table = QTableWidget(self) + self.table.setColumnCount(1) + self.table.setRowCount(1) + + self.table.setHorizontalHeaderLabels(["Info"]) + + # Set the tooltips to headings + self.table.horizontalHeaderItem(0).setToolTip("Info") + + # Set the alignment to the headers + self.table.horizontalHeaderItem(0).setTextAlignment(Qt.AlignHCenter) + + + grid_layout.addWidget(self.table, 0, 0) # Adding the table to the grid + + # Position the window to the right of the parent window + self.position_relative_to_parent(parent_window) + + def position_relative_to_parent(self, parent_window): + # Get the geometry of the parent window + parent_frame = parent_window.frameGeometry() + + # Calculate new position (right of parent window with a small gap) + new_x = parent_frame.x() + parent_frame.width() + 5 + new_y = parent_frame.y() + + # Move the window to the new position + self.move(new_x, new_y) + + def load_data(self, neo_data): + for i, node_data in enumerate(neo_data): + row_number = self.table.rowCount()-1 + if len(neo_data) != self.table.rowCount(): + self.table.insertRow(row_number) + self.table.setItem(row_number, 0, QTableWidgetItem(str(node_data[0]["title"]))) + + self.table.resizeColumnsToContents() + if __name__ == "__main__": import sys @@ -143,7 +206,8 @@ if __name__ == "__main__": createuUiversityDB(conn) - conn = psycopg2.connect("user=postgres dbname=university password=456 host=localhost port=5432") + conn = psycopg2.connect("user={0} dbname={1} password={2} host={3} port={4}".format(POSTGRES_USER, POSTGRES_DB, + POSTGRES_PASS, POSTGRES_HOST, POSTGRES_PORT)) createUsersTable(conn) @@ -157,4 +221,16 @@ if __name__ == "__main__": mw = MainWindow() mw.load_data(users) mw.show() + + URI = NEO_HOST + AUTH = (NEO_USER, NEO_PASS) + + with GraphDatabase.driver(URI, auth=AUTH) as driver: + records, summary, keys = driver.execute_query( + "MATCH (nineties:Movie) WHERE nineties.released >= 1990 AND nineties.released < 2000 RETURN nineties" + ) + + neo_window = NeoWindow(mw) + neo_window.load_data(records) + neo_window.show() sys.exit(app.exec()) \ No newline at end of file diff --git a/neo_form.png b/neo_form.png new file mode 100644 index 0000000000000000000000000000000000000000..eab1d9de298a40cd093d5f8ed0a21981b5cbb990 GIT binary patch literal 8102 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 Pe?Me+#Z<3M2O9CO)(r50 literal 0 HcmV?d00001