updated to mysql-connector-python
This commit is contained in:
1 parent
65691a0aee
commit
4bc9b87317
6 files changed
+50
-38
No files matched your search
@@ -6,7 +6,7 @@ Tables 9.3–9.5 (STUDENT, GUARDIAN, ATTENDANCE).
|
||||
|
||||
## What it does on startup
|
||||
|
||||
1. Connects to the MySQL server at `10.0.1.40:3306`.
|
||||
1. Connects to the MySQL server at `10.10.0.160:3306`.
|
||||
2. Verifies the `student_db` database exists — creates it if not.
|
||||
3. Verifies the `GUARDIAN`, `STUDENT`, and `ATTENDANCE` tables exist
|
||||
(in that order, since STUDENT references GUARDIAN and ATTENDANCE
|
||||
@@ -31,7 +31,7 @@ Tables 9.3–9.5 (STUDENT, GUARDIAN, ATTENDANCE).
|
||||
export DB_USER=root
|
||||
export DB_PASSWORD=your_password_here
|
||||
# optional overrides — these already default correctly:
|
||||
# export DB_HOST=10.0.1.40
|
||||
# export DB_HOST=10.10.0.160
|
||||
# export DB_PORT=3306
|
||||
# export DB_NAME=student_db
|
||||
```
|
||||
@@ -72,12 +72,6 @@ cascades and removes their attendance records automatically.
|
||||
|
||||
## Notes
|
||||
|
||||
- Uses [PyMySQL](https://pymysql.readthedocs.io/), a pure-Python MySQL
|
||||
client — no system libraries (like `libmysqlclient`) required.
|
||||
- All input is validated against the schema's constraints (max lengths,
|
||||
digit counts, date format, P/A status) before hitting the database,
|
||||
and database-level errors (duplicate keys, foreign key violations)
|
||||
are caught and shown as friendly messages rather than crashing.
|
||||
- Tested end-to-end (connect → create DB/tables → full CRUD → constraint
|
||||
error handling → cascade delete) against a local MySQL/MariaDB
|
||||
instance before delivery.
|
||||
- Uses [mysql-connector-python](https://dev.mysql.com/doc/connector-python/en/), Oracle's official pure-Python MySQL driver — no system libraries (like `libmysqlclient`) required.
|
||||
- All input is validated against the schema's constraints (max lengths, digit counts, date format, P/A status) before hitting the database, and database-level errors (duplicate keys, foreign key violations) are caught and shown as friendly messages rather than crashing.
|
||||
- Tested end-to-end (connect → create DB/tables → full CRUD → constraint error handling → cascade delete) against a local MySQL/MariaDB instance before delivery.
|
||||
@@ -5,12 +5,17 @@ Connection settings are read from environment variables first, falling back
|
||||
to the defaults below (which match the assignment's requirements). This
|
||||
means you can run the app as-is, or override any value like:
|
||||
|
||||
DB_HOST=10.0.1.40 DB_USER=root DB_PASSWORD=secret python3 main.py
|
||||
DB_HOST=10.10.0.160 DB_USER=root DB_PASSWORD=secret python3 main.py
|
||||
|
||||
# on windows
|
||||
$env:DB_USER="mysql_user"
|
||||
$env:DB_PASSWORD="mysql_password"
|
||||
python3 main.py
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
DB_HOST = os.environ.get("DB_HOST", "10.0.1.40")
|
||||
DB_HOST = os.environ.get("DB_HOST", "10.10.0.160")
|
||||
DB_PORT = int(os.environ.get("DB_PORT", "3306"))
|
||||
DB_USER = os.environ.get("DB_USER", "root")
|
||||
DB_PASSWORD = os.environ.get("DB_PASSWORD", "")
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
"""
|
||||
CRUD operations for GUARDIAN, STUDENT and ATTENDANCE.
|
||||
|
||||
Every function takes an open pymysql connection as its first argument and
|
||||
manages its own commit/rollback. All functions return plain data
|
||||
(dicts/lists/bool) so this module has no dependency on the UI layer.
|
||||
Every function takes an open mysql-connector-python connection as its first
|
||||
argument and manages its own commit/rollback. All functions return plain
|
||||
data (dicts/lists/bool) so this module has no dependency on the UI layer.
|
||||
"""
|
||||
|
||||
import pymysql
|
||||
import mysql.connector
|
||||
|
||||
|
||||
class CrudError(Exception):
|
||||
@@ -20,8 +20,8 @@ def _run(conn, sql, params=None, fetch=None):
|
||||
fetch: None (no fetch), 'one', or 'all'
|
||||
Translates common MySQL errors into CrudError with a friendly message.
|
||||
"""
|
||||
cur = conn.cursor(dictionary=True)
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql, params or ())
|
||||
result = None
|
||||
if fetch == "one":
|
||||
@@ -30,23 +30,24 @@ def _run(conn, sql, params=None, fetch=None):
|
||||
result = cur.fetchall()
|
||||
conn.commit()
|
||||
return result if fetch else cur.rowcount
|
||||
except pymysql.err.IntegrityError as e:
|
||||
except mysql.connector.errors.IntegrityError as e:
|
||||
conn.rollback()
|
||||
code = e.args[0] if e.args else None
|
||||
if code == 1062:
|
||||
if e.errno == 1062:
|
||||
raise CrudError("A record with that primary/unique key already exists.")
|
||||
if code in (1451, 1452):
|
||||
if e.errno in (1451, 1452):
|
||||
raise CrudError(
|
||||
"That operation violates a foreign key constraint "
|
||||
"(referenced record missing, or still referenced by other rows)."
|
||||
)
|
||||
raise CrudError(f"Database integrity error: {e}")
|
||||
except pymysql.err.DataError as e:
|
||||
except mysql.connector.errors.DataError as e:
|
||||
conn.rollback()
|
||||
raise CrudError(f"Invalid data for one or more fields: {e}")
|
||||
except pymysql.err.MySQLError as e:
|
||||
except mysql.connector.Error as e:
|
||||
conn.rollback()
|
||||
raise CrudError(f"Database error: {e}")
|
||||
finally:
|
||||
cur.close()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- GUARDIAN --
|
||||
|
||||
@@ -13,8 +13,8 @@ Schema notes:
|
||||
|
||||
import sys
|
||||
|
||||
import pymysql
|
||||
import pymysql.cursors
|
||||
import mysql.connector
|
||||
from mysql.connector import errorcode
|
||||
|
||||
import config
|
||||
|
||||
@@ -61,18 +61,23 @@ TABLE_ORDER = ["GUARDIAN", "STUDENT", "ATTENDANCE"]
|
||||
def connect_server(database=None):
|
||||
"""Connect to the MySQL server (optionally selecting a database)."""
|
||||
try:
|
||||
conn = pymysql.connect(
|
||||
conn = mysql.connector.connect(
|
||||
host=config.DB_HOST,
|
||||
port=config.DB_PORT,
|
||||
user=config.DB_USER,
|
||||
password=config.DB_PASSWORD,
|
||||
database=database,
|
||||
connect_timeout=config.DB_CONNECT_TIMEOUT,
|
||||
cursorclass=pymysql.cursors.DictCursor,
|
||||
connection_timeout=config.DB_CONNECT_TIMEOUT,
|
||||
autocommit=False,
|
||||
)
|
||||
return conn
|
||||
except pymysql.err.OperationalError as e:
|
||||
except mysql.connector.Error as e:
|
||||
if e.errno == errorcode.ER_ACCESS_DENIED_ERROR:
|
||||
print(f"\n[ERROR] Access denied for user '{config.DB_USER}' — check "
|
||||
f"DB_USER/DB_PASSWORD.")
|
||||
elif database and e.errno == errorcode.ER_BAD_DB_ERROR:
|
||||
print(f"\n[ERROR] Database '{database}' does not exist.")
|
||||
else:
|
||||
print(f"\n[ERROR] Could not connect to MySQL server at "
|
||||
f"{config.DB_HOST}:{config.DB_PORT} as user '{config.DB_USER}'.")
|
||||
print(f" Details: {e}")
|
||||
@@ -83,7 +88,8 @@ def ensure_database():
|
||||
"""Verify the student_db database exists; create it if it does not."""
|
||||
conn = connect_server(database=None)
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur = conn.cursor()
|
||||
try:
|
||||
cur.execute("SHOW DATABASES LIKE %s", (config.DB_NAME,))
|
||||
exists = cur.fetchone() is not None
|
||||
if exists:
|
||||
@@ -96,23 +102,29 @@ def ensure_database():
|
||||
)
|
||||
conn.commit()
|
||||
print(f"[OK] Database '{config.DB_NAME}' created.")
|
||||
finally:
|
||||
cur.close()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
def ensure_tables(conn):
|
||||
"""Verify each required table exists; create any that are missing."""
|
||||
with conn.cursor() as cur:
|
||||
cur = conn.cursor()
|
||||
cur.execute("SHOW TABLES")
|
||||
existing = {row[f"Tables_in_{config.DB_NAME}"] for row in cur.fetchall()}
|
||||
existing = {row[0] for row in cur.fetchall()}
|
||||
cur.close()
|
||||
|
||||
for table in TABLE_ORDER:
|
||||
if table in existing:
|
||||
print(f"[OK] Table '{table}' found.")
|
||||
else:
|
||||
print(f"[..] Table '{table}' not found. Creating it...")
|
||||
with conn.cursor() as cur:
|
||||
cur = conn.cursor()
|
||||
try:
|
||||
cur.execute(TABLE_DEFINITIONS[table])
|
||||
finally:
|
||||
cur.close()
|
||||
conn.commit()
|
||||
print(f"[OK] Table '{table}' created.")
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Student Management System
|
||||
==========================
|
||||
Terminal CRUD application for STUDENT / GUARDIAN / ATTENDANCE, backed by
|
||||
MySQL on 10.0.1.40:3306 (student_db).
|
||||
MySQL on 10.10.0.160:3306 (student_db).
|
||||
|
||||
On startup this:
|
||||
1. Connects to the MySQL server.
|
||||
@@ -17,7 +17,7 @@ Run:
|
||||
|
||||
import sys
|
||||
|
||||
import pymysql
|
||||
import mysql.connector
|
||||
|
||||
import crud
|
||||
import db
|
||||
@@ -326,7 +326,7 @@ def main():
|
||||
main_menu(conn)
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nInterrupted. Exiting.")
|
||||
except pymysql.err.MySQLError as e:
|
||||
except mysql.connector.Error as e:
|
||||
print(f"\n[ERROR] Lost database connection: {e}")
|
||||
sys.exit(1)
|
||||
finally:
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
PyMySQL>=1.1.0
|
||||
mysql-connector-python>=9.0.0
|
||||
Reference in new issue
Block a user