I wrote a small database manager, using SQLite, and it worked fine. After adding the last 2 fields (sq_idA , sq_idB), it is now locked. Before adding these two, everything was ok.
The problem will be trivial. I know that SQLite cannot perform many simultaneous transitions and is a lightweight database, but my database manager is also very small and lightweight. So the problem will be something in the code I wrote. Maybe it's because I didn't use conn.close? I'm just starting out with databases. However the error is found:
sqlite3.OperationalError: database is locked
Sorry if the code uses elements written not in English. The elements that I need to save are: campionato, giornata, calendario, ore, minuti, squadra_casa, squadra_fuori, ris_sq_casa, ris_sq_fuori, id_campionato, id_giornata. So far it worked fine, all ok, and the database hadn't crashed.
PROBLEM: After adding sq_idA, sq_idB, the database crashed. To be precise, it crashes when I insert a new record and click on the "Add" button. Before adding id_sqA, id_sqB, it worked fine, without problems. I want to specify that varoius combobox adds: campionato, giornata, calendario, ore, minuti, squadra_casa, squadra_fuori, ris_sq_casa, ris_sq_fuori. While id_campionato, id_giornata, id_sqA, id_sqB are added automatically by extracting the id.
The database manager consists of two files: main.py and db.py. I add the complete and directly executable code
MAIN.PY
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
import tkinter as tk
from tkinter import ttk
from db import Database
import sqlite3
from PIL import ImageTk, Image
from tkcalendar import DateEntry
from datetime import date
db = Database('/database.db')
con = sqlite3.connect('database.db')
cursor = con.cursor()
root = Tk()
root.title("Gestione partite")
root.geometry("1920x1080+0+0")
root.config(bg="white")
root.state("normal")
#######################################
#StringVar
campionato = StringVar()
giornata = StringVar()
calendario = StringVar()
ore = StringVar()
minuti = StringVar()
squadra_casa = StringVar()
squadra_fuori = StringVar()
ris_sq_casa = StringVar()
ris_sq_fuori = StringVar()
squadracasa = StringVar()
squadrafuori = StringVar()
#######################################
#Functions
def combo_campionati():
campionato = combo_Campionato.get()
cursor.execute('SELECT Nome_Campionato FROM ARCHIVIO_CAMPIONATI')
result=[row[0] for row in cursor]
return result
def id_campionati():
campionato = combo_Campionato.get()
cursor.execute('SELECT ID_Campionato FROM ARCHIVIO_Campionati WHERE Nome_Campionato=?',(campionato,))
result=[row[0] for row in cursor]
return result[0]
def combo_squadre(event=None):
campionato = combo_Campionato.get()
cursor.execute('''
SELECT s.Nome_Squadra FROM ARCHIVIO_Squadre_Campionato s, ARCHIVIO_CAMPIONATI c
WHERE s.ID_Campionato=c.ID_Campionato AND c.Nome_Campionato = ?''', (campionato,))
result=[row[0] for row in cursor]
combo_NomeSquadra_Casa['values'] = result
combo_NomeSquadra_Fuori['values'] = result
return result
def combo_giornateee(event=None):
# get all Number_Round for selected tournament
cursor.execute('''
SELECT Numero_Giornata From ARCHIVIO_Giornate r, ARCHIVIO_Campionati t
WHERE r.ID_Campionato = t.ID_Campionato AND Nome_Campionato = ?''', (campionato.get(),))
result=[row[0] for row in cursor]
combo_Giornate['value'] = result # update combo_Rounds
combo_Giornate.set('Select') # reset Rounds selection
return result
def id_giornate(event=None):
# get the ID_Round based on selected tournament and Number_Round
cursor.execute('''
SELECT ID_Giornata FROM ARCHIVIO_Giornate r, ARCHIVIO_CAMPIONATI t
WHERE r.ID_Campionato = t.ID_Campionato AND Numero_Giornata = ? AND Nome_Campionato = ?''',
(giornata.get(), campionato.get()))
result = cursor.fetchone()
if result:
print(result[0])
return result[0]
return None
def id_sqAAA(event=None):
# get the ID_Round based on selected tournament and Number_Round
squadracasa = combo_NomeSquadra_Casa.get()
cursor.execute('SELECT ID_Sq FROM ARCHIVIO_Squadre_Campionato WHERE Nome_Squadra=?', (squadracasa,))
result = cursor.fetchone()
if result:
print(result[0])
return result[0]
return None
def id_sqBBB(event=None):
# get the ID_Round based on selected tournament and Number_Round
squadrafuori = combo_NomeSquadra_Fuori.get()
cursor.execute('SELECT ID_Sq FROM ARCHIVIO_Squadre_Campionato WHERE Nome_Squadra=?', (squadrafuori,))
result = cursor.fetchone()
if result:
print(result[0])
return result[0]
return None
def filtracampionati():
tv.delete(*tv.get_children())
campionati = combo_Campionato.get()
giornate = combo_Giornate.get()
cursor.execute('SELECT * FROM ARCHIVIO_Risultati WHERE campionato=? AND giornata=?',(campionati, giornate,))
for row in cursor:
tv.insert("", END, values=row)
#######################################
#Graphics of the two upper bars
#Barre sopra
barrasopra=Frame(root, width=2200, height=47, background="#333333")
barrasopra.place(x=0, y=0)
barra_seconda=Frame(root, width=2200, height=47, background="#eb5c00")
barra_seconda.place(x=0, y=47)
#Icona search
lenteingrandimento= tk.PhotoImage(file="/home/xxxxxx/Scrivania/xxxxxxx/img/search-icon2.png")
btn0 = tk.Button(root, image=lenteingrandimento, borderwidth=0, highlightthickness=0, bg="#E95420", command=filtracampionati)
btn0.place(x=730, y=55)
#Combobox Campionati
lbl_Campionato = Label(root, text="Campionato", font=("Calibri", 11), bg="#E95420", fg="white")
lbl_Campionato.place(x=6, y=60)
combo_Campionato = ttk.Combobox(root, font=("Calibri", 11), width=20, textvariable=campionato, state="readonly")
combo_Campionato.place(x=110, y=60)
combo_Campionato.set("Seleziona campionato")
combo_Campionato['values'] = combo_campionati()
combo_Campionato.bind('<<ComboboxSelected>>', combo_squadre, combo_giornateee)
combo_Campionato.bind('<<ComboboxSelected>>', combo_giornateee, add=True)
#Combobox Squadre combinate
combo_NomeSquadra_Casa = ttk.Combobox(root, font=("Calibri", 11), width=17, textvariable=squadra_casa, state="readonly")
combo_NomeSquadra_Casa.place(x=6, y=225)
combo_NomeSquadra_Casa.set("Squadra Casa")
combo_NomeSquadra_Fuori = ttk.Combobox(root, font=("Calibri", 11), width=17, textvariable=squadra_fuori, state="readonly")
combo_NomeSquadra_Fuori.place(x=210, y=225)
combo_NomeSquadra_Fuori.set("Squadra Fuori")
#Combobox Giornate
lbl_Giornate = Label(root, text="Giornate", font=("Calibri", 11), bg="#E95420", fg="white")
lbl_Giornate.place(x=430, y=60)
combo_Giornate = ttk.Combobox(root, font=("Calibri", 11), width=20, textvariable=giornata, state="readonly") #ho tolto textvariable=giornate
combo_Giornate.place(x=510, y=60)
combo_Giornate.set("Seleziona giornata")
combo_Giornate['values'] = combo_campionati()
####################################################
#Window body graphics
labelframe = LabelFrame(root, text="Data e orario", width=400,height=90, bg="white", foreground='#eb5c00')
labelframe.place(x=8, y=120)
#calendario
lbl_Calendario = Label(root, text="Data", font=("Calibri", 11), bg="white", fg="black")
lbl_Calendario.place(x=15, y=143)
class MyDateEntry(DateEntry):
def __init__(self, master=None, **kw):
DateEntry.__init__(self, master=None, **kw)
# add black border around drop-down calendar
self._top_cal.configure(bg='black', bd=1)
# add label displaying today's date below
tk.Label(self._top_cal, bg='#77c030', anchor='w',
text='Oggi: %s' % date.today().strftime('%x')).pack(fill='x')
# create the entry and configure the calendar colors
de = MyDateEntry(root, year=2021, month=9, day=6, textvariable=calendario,
selectbackground='#77c030',
selectforeground='black',
normalbackground='white',
normalforeground='black',
background='#77c030',
foreground='black',
bordercolor='#77c030',
othermonthforeground='gray50',
othermonthbackground='white',
othermonthweforeground='gray50',
othermonthwebackground='white',
weekendbackground='white',
weekendforeground='black',
headersbackground='white',
headersforeground='gray70')
de.pack()
de.place(x=15, y=170)
#Ore
lbl_Ora = Label(root, text="Orario", font=("Calibri", 11), bg="white", fg="black")
lbl_Ora.place(x=197, y=143)
combo_Orario_Ora = ttk.Combobox(root, font=("Calibri", 11), width=7, textvariable=ore, state="readonly")
combo_Orario_Ora['values'] = ("01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "00")
combo_Orario_Ora.place(x=200, y=170)
combo_Orario_Ora.set("Ora")
#Minuti
combo_Orario_Minuti = ttk.Combobox(root, font=("Calibri", 11), width=7, textvariable=minuti, state="readonly")
combo_Orario_Minuti['values'] = ("00", "05", "10", "15", "20", "30", "40", "45", "50")
combo_Orario_Minuti.place(x=300, y=170)
combo_Orario_Minuti.set("Minuti")
#Partita
lbl_Risultato_Sq_A = Label(root, text="Partita", font=("Calibri", 11), bg="white", fg="black")
lbl_Risultato_Sq_A.place(x=6, y=200)
#Risultato Sq A
lbl_Risultati = Label(root, text="Risultato Finale", font=("Calibri", 11), bg="white", fg="black")
lbl_Risultati.place(x=6, y=290)
combo_Risultato_Sq_A = ttk.Combobox(root, font=("Calibri", 11), width=7, textvariable=ris_sq_casa, state="readonly")
combo_Risultato_Sq_A['values'] = ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12")
combo_Risultato_Sq_A.place(x=6, y=315)
#Risultato Sq B
combo_Risultato_Sq_B = ttk.Combobox(root, font=("Calibri", 11), width=7, textvariable=ris_sq_fuori, state="readonly")
combo_Risultato_Sq_B['values'] = ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11")
combo_Risultato_Sq_B.place(x=120, y=315)
#####################################################
#Insert in Database
def getData(event):
selected_row = tv.focus()
data = tv.item(selected_row)
global row
row = data["values"]
#print(row)
campionato.set(row[1])
giornata.set(row[2])
calendario.set(row[3])
ore.set(row[4])
minuti.set(row[5])
squadra_casa.set(row[6])
squadra_fuori.set(row[7])
ris_sq_casa.set(row[8])
ris_sq_fuori.set(row[9])
def dispalyAll():
tv.delete(*tv.get_children())
for row in db.fetch():
tv.insert("", END, values=row)
def add_employee():
if combo_Campionato.get() == "" or combo_Giornate.get() == "" or de.get() == "" or combo_Orario_Ora.get() == "" or combo_Orario_Minuti.get() == "" or combo_NomeSquadra_Casa.get() == "" or combo_NomeSquadra_Fuori.get() == "" or combo_Risultato_Sq_A.get() == "" or combo_Risultato_Sq_B.get() == "":
messagebox.showerror("Hai mancato qualcosa", "Compila tutti i campi")
return
id_campionati_value=id_campionati()
id_rounds_value=id_giornate()
id_sqA_value=id_sqAAA()
id_sqB_value=id_sqBBB()
db.insert(campionato.get(), giornata.get(), de.get(),combo_Orario_Ora.get(), combo_Orario_Minuti.get(), combo_NomeSquadra_Casa.get(), combo_NomeSquadra_Fuori.get(), combo_Risultato_Sq_A.get(), combo_Risultato_Sq_B.get(), id_campionati_value, id_rounds_value, id_sqA_value, id_sqB_value)
messagebox.showinfo("Partita inserita correttattamente", "Record Inserted")
clearAll()
dispalyAll()
def update_employee():
if combo_Campionato.get() == "" or combo_Giornate.get() == "" or de.get() == "" or combo_Orario_Ora.get() == "" or combo_Orario_Minuti.get() == "" or combo_NomeSquadra_Casa.get() == "" or combo_NomeSquadra_Fuori.get() == "" or combo_Risultato_Sq_A.get() == "" or combo_Risultato_Sq_B.get() == "":
messagebox.showerror("Hai mancato qualcosa", "Compila tutti i campi")
return
id_campionati_value=id_campionati()
id_rounds_value=id_giornate()
db.update(row[0],combo_Campionato.get(),combo_Giornate.get(), de.get() , combo_Orario_Ora.get() ,combo_Orario_Minuti.get(), combo_NomeSquadra_Casa.get(), combo_NomeSquadra_Fuori.get(), combo_Risultato_Sq_A.get(), combo_Risultato_Sq_B.get(), id_campionati_value, id_rounds_value)
messagebox.showinfo("Success", "Record Update")
clearAll()
dispalyAll()
def delete_employee():
db.remove(row[0])
clearAll()
dispalyAll()
def clearAll():
campionato.set("")
giornata.set("")
calendario.set("")
ore.set("")
minuti.set("")
squadra_casa.set("")
squadra_fuori.set("")
ris_sq_casa.set("")
ris_sq_fuori.set("")
##########################################
#Buttons
btnAdd = Button(root, command=add_employee, text="Aggiungi", width=12, font=("Calibri", 10, "bold"), fg="white",
bg="#E95420", bd=0).place(x=5, y=10)
btnEdit = Button(root, command=update_employee, text="Modifica", width=12, font=("Calibri", 10, "bold"),
fg="white", bg="#E95420",
bd=0).place(x=150, y=10)
btnDelete = Button(root, command=delete_employee, text="Elimina", width=12, font=("Calibri", 10, "bold"),
fg="white", bg="#E95420",
bd=0).place(x=300, y=10)
btnClear = Button(root, command=clearAll, text="Pulisci", width=12, font=("Calibri", 10, "bold"), fg="white",
bg="#E95420",
bd=0).place(x=450, y=10)
###########################################
# Table Frame
tree_frame = Frame(root, bg="#ecf0f1")
tree_frame.place(x=0, y=570, width=1980, height=520)
style = ttk.Style()
style.configure("mystyle.Treeview", font=('Calibri', 11),
rowheight=50) # Modify the font of the body
style.configure("mystyle.Treeview.Heading", font=('Calibri', 11)) # Modify the font of the headings
tv = ttk.Treeview(tree_frame, columns=(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), style="mystyle.Treeview")
tv.heading("1", text="ID")
tv.column("1", width=5)
tv.heading("2", text="Campionato")
tv.column("2", width=70)
tv.heading("3", text="Giornata")
tv.column("3", width=70)
tv.heading("4", text="Data")
tv.column("4", width=70)
tv.heading("5", text="Ora")
tv.column("5", width=70)
tv.heading("6", text="Minuti")
tv.column("6", width=70)
tv.heading("7", text="Squadra Casa")
tv.column("7", width=70)
tv.heading("8", text="Squadra Ospite")
tv.column("8", width=70)
tv.heading("9", text="Risultato Sq Casa")
tv.column("9", width=70)
tv.heading("10", text="Risultato Sq Ospite")
tv.column("10", width=70)
tv.heading("11", text="id_campionato")
tv.column("11", width=70)
tv.heading("12", text="id_giornata")
tv.column("12", width=70)
tv.heading("13", text="id_sqA")
tv.column("13", width=70)
tv.heading("14", text="id_sqB")
tv.column("14", width=70)
tv['show'] = 'headings'
tv.bind("<ButtonRelease-1>", getData)
tv.pack(fill=X)
#COLORE TABELLA
style = ttk.Style(root)
style.configure("Treeview",
background="white",
foreground="#000000",
rowheight=25,
fieldbackground="white")
style.map('Treeview', background=[('selected', '#eb5c00')])
dispalyAll()
root.mainloop()
DB.PY
import sqlite3
class Database:
def __init__(self, db):
self.con = sqlite3.connect(db)
self.cur = self.con.cursor()
sql = """
CREATE TABLE IF NOT EXISTS employees(
ID Integer Primary Key,
campionato integer,
giornata integer,
calendario integer,
ore integer,
minuti integer,
squadra_casa integer,
squadra_fuori integer,
ris_sq_casa integer,
ris_sq_fuori integer,
id_campionato integer,
id_giornata integer,
id_sqA integer,
id_sqB integer
)
"""
self.cur.execute(sql)
self.con.commit()
# Insert Function
def insert(self, campionato, giornata, calendario, ore, minuti, squadra_casa, squadra_fuori, ris_sq_casa, ris_sq_fuori, id_campionato, id_giornata, id_sqA, id_sqB):
self.cur.execute("insert into ARCHIVIO_Risultati values (NULL,?,?,?,?,?,?,?,?,?,?,?,?,?)",
(campionato, giornata, calendario, ore, minuti, squadra_casa, squadra_fuori, ris_sq_casa, ris_sq_fuori, id_campionato, id_giornata, id_sqA, id_sqB))
self.con.commit()
# Fetch All Data from DB
def fetch(self):
self.cur.execute("SELECT * from ARCHIVIO_Risultati")
rows = self.cur.fetchall()
# print(rows)
return rows
#I don't write the DELETE and UPDATE code so as not to dwell on it
How to solve? Thank you
UPDATE: I add the 4 necessary tables of the database code to create a playable example between main.py, db.py and sqlite database update
CREATE TABLE "ARCHIVIO_Campionati" (
"ID_Campionato" INTEGER,
"Nome_Campionato" TEXT,
PRIMARY KEY("ID_Campionato" AUTOINCREMENT)
);
CREATE TABLE "ARCHIVIO_Squadre_Campionato" (
"ID_Sq" INTEGER,
"Nome_Squadra" TEXT,
"Campionato" INTEGER,
"ID_Campionato" INTEGER,
PRIMARY KEY("ID_Sq" AUTOINCREMENT),
CREATE TABLE "ARCHIVIO_Giornate" (
"ID_Giornata" INTEGER,
"Numero_Giornata" INTEGER,
"ID_Campionato" INTEGER,
PRIMARY KEY("ID_Giornata" AUTOINCREMENT),
"ARCHIVIO_Campionati"("ID_Campionato")
);
CREATE TABLE "ARCHIVIO_Risultati" (
"ID" INTEGER,
"campionato" INTEGER,
"giornata" INTEGER,
"calendario" INTEGER,
"ore" INTEGER,
"minuti" INTEGER,
"squadra_casa" INTEGER,
"squadra_fuori" INTEGER,
"ris_sq_casa" INTEGER,
"ris_sq_fuori" INTEGER,
"id_campionato" INTEGER,
"id_giornata" INTEGER,
"id_sqA" INTEGER,
"id_sqB" INTEGER,
PRIMARY KEY("ID" AUTOINCREMENT)
);