I have a data access object in Python/SQLite3 defined as:
import sqlite3
class Dao:
VEHICLE_TABLE_SCHEMA = """
CREATE TABLE IF NOT EXISTS vehicles (
vehicle_key integer NOT NULL PRIMARY KEY AUTOINCREMENT,
vehicle_description TEXT NOT NULL
)
"""
VEHICLE_INSERT_SQL = "INSERT INTO vehicles (vehicle_description) VALUES (?)"
VEHICLE_LIST_SQL = "SELECT * FROM vehicles"
MILAGE_TABLE_SCHEMA = """
CREATE TABLE IF NOT EXISTS milage (
milage_date DATE NOT NULL PRIMARY KEY,
vehicle_id INTEGER NOT NULL,
milage integer NOT NULL
)
"""
MILAGE_INSERT_SQL = "INSERT INTO milage ( milage_date , vehicle_id , milage ) VALUES (? , ? , ? )"
def __init__(self, dbname = "vehicles.sqlite3" ):
# self.conn = sqlite3.connect(dbname, autocommit=True)
self.create_table_if_missing( self.MILAGE_TABLE_SCHEMA )
self.create_table_if_missing( self.VEHICLE_TABLE_SCHEMA )
self.dbname = dbname
def create_table_if_missing(self , sql ):
#Creates the 'vehicle' table in the database if it doesn't exist."""
with sqlite3.connect(self.dbname) as conn:
cursor = conn.cursor()
cursor.execute( sql )
def add_vehicle(self , description ):
with sqlite3.connect(self.dbname) as conn:
cursor = conn.cursor()
cursor.execute( self.VEHICLE_INSERT_SQL , ( description , ) )
def add_milage(self , milage_date , vehicle_id , milage ):
with sqlite3.connect(self.dbname) as conn:
cursor = conn.cursor()
cursor.execute( self.MILAGE_INSERT_SQL , ( milage_date , vehicle_id , milage ) )
def list_vehicles(self):
with sqlite3.connect(self.dbname) as conn:
cursor = conn.cursor()
cursor.execute( self.VEHICLE_LIST_SQL )
return cursor.fetchall()
I try calling it from a class called MilageEntryFrame shown in part below:
import customtkinter as ctk
from dao import Dao
class MilageEntryFrame( ctk.CTkFrame ):
def __init__(self, master, **kwargs):
super().__init__(master, **kwargs)
self.frm_milage_entry = ctk.CTkFrame(self )
self.frm_milage_entry.pack(fill="x", padx=5, pady=25)
vehicle_records = Dao.list_vehicles( self )
I get an error stating:
File "D:\PycharmProjects\VehicleMaint\MilageEntryFrame.py", line 12, in __init__
vehicle_records = Dao.list_vehicles( self )
File "D:\PycharmProjects\VehicleMaint\dao.py", line 57, in list_vehicles
with sqlite3.connect(self.dbname) as conn:
^^^^^^^^^^^
AttributeError: 'MilageEntryFrame' object has no attribute 'dbname'. Did you mean: '_name'?
The first thing to catch my eye is it saying MilageEntryFrame has no attribute 'dbname'. This is correct, it doesn't have it, nor should it need it as it is set in the DAO class, not in the MilageEntryFrame. I'm guessing it has something to do with my passing self from the MilageEntryFrame class to the DAO class. But, it complains if I don't pass it. Coincidentally, I asked ChatGPT to create a DAO class to do what I'm seeking and it's response was virtually identical to my code. I've converted my code to try using with rather than the try/catch I originally had and that ChatGPT had as well.
The issue is that you can't just substitute self
between classes. self
isn't something magical, it's just the naming convention for the parameter holding a reference to the object a member function/method is invoked on.
In your case, Dao.list_vehicles
expects self
to be an instance of the Dao
class, but you're explicitly passing it an instance of MilageEntryFrame
.
>>> class MyClass:
... def some_method(self):
... pass
...
>>> type(MyClass.some_method)
<class 'function'>
>>> type(MyClass().some_method)
<class 'method'>
Effectively, you're circumventing the Python interpreter's implicit passing of self
when you're calling list_vehicles
on the class itself and not an instance of that class.
You want something more like:
import customtkinter as ctk
from dao import Dao
class MilageEntryFrame( ctk.CTkFrame ):
def __init__(self, master, **kwargs):
super().__init__(master, **kwargs)
self.frm_milage_entry = ctk.CTkFrame(self )
self.frm_milage_entry.pack(fill="x", padx=5, pady=25)
vehicle_records = Dao().list_vehicles() # Notice the added '()' and the removed `self`
As @ticktalk points out in their comment on the post, there are also other issues with the order of initialization that you'll run into once you actually instantiate Dao
, so this is the answer to the question as posted, but your script won't run until you fix also the other issue(s).