Displaying sqlite3 data into Treeview - python-3.x

I am writing some code that shows a list of food with their information.
My code:
-connects to data base and gets items successfully
-loops correctly
Problem:
-If the name of my product is one word (ex:eggs) my code displays everything in the correct column
-If the name of my product is two or more words (ex:frosted flakes) my code displays 'frosted' on first column then 'flakes' in next columns which is incorrect
from tkinter import ttk
import tkinter as tk
import sqlite3
try:
from Tkinter import *
except ImportError:
from tkinter import *
def View():
db = sqlite3.connect("food_data.db")
cursor = db.cursor()
cursor.execute("SELECT name, quantity, expdate FROM food ORDER BY expdate ASC")
for row in cursor:
disp=('{0} {1} {2}'.format(row[0], row[1], row[2]))
tree.insert("",tk.END, values=disp)
db.close()
root = tk.Tk()
root.geometry("800x480")
tree = ttk.Treeview(column=("column1","column2","column3"),show='headings')
tree.heading("#1", text="Name")
tree.heading("#2", text="Quantity")
tree.heading("#3", text="Expiration Date")
tree.pack()
b2 = tk.Button(text="view data", command=View)
b2.pack()
root.mainloop()
It is suppose to successfully display items with multiple words in their name onto one column and not carry to the next one.

def View():
db = sqlite3.connect("food_data.db")
cursor = db.cursor()
cursor.execute("SELECT name, quantity, expdate FROM food ORDER BY expdate ASC")
for row in cursor:
# disp=('{0} {1} {2}'.format(row[0], row[1], row[2]))
tree.insert("",tk.END, values=(row[0], row[1], row[2]))
db.close()
Do it this way rather you have to insert the content in the treeview as tuple or list after iterating over it.
tree.insert("",tk.END, values=(row[0], row[1], row[2]))

Related

python sqlite3 record is not inserting into the database with a placeholder function

this code is not inserting my list(self.list2) into the database 'main.db'. I read the the following posts already and they all seem to use the idea of using join() to create # of place holders based on the length of the list.
Dynamically creating a placeholder to insert many column values for a row in SQLite table
Inserting to sqlite dynamically with Python 3
the code is running without errors.
I tested the code by printing
return (f"{', '.join('?' * len(input))}")
and it prints "?, ?, ?, ? ", so I know the function works.
the database is created properly with the following code:
self.cursor.execute('''CREATE TABLE IF NOT EXISTS main
(T_num text Primary Key NOT NULL,
Name text NOT NULL,
Item1 text,
Item2 text,
Item3 text)''')
Maybe I missed a small detail, or I don't know how the return statement/function works.
Please help me to trouble shoot this. Thank you for any assistance.
import tkinter as tk
import sqlite3
class Model():
def __init__(self):
self.list1 = [('Table #', '6'), ('Name', 'Jenn'), ('Beef
Tacos', '6'), ("Fish Tacos", "6")]
self.list2 = list(map(": ".join, self.list1))
self.conn = sqlite3.connect("4th.db")
self.cursor=self.conn.cursor()
self.place_holder(self.list2)
def place_holder(self, input):
return (f"{', '.join('?' * len(input))}")
self.cursor.execute("INSERT INTO main VALUES (place_holder(input))", self.list2)
self.conn.commit()
self.conn.close()
if __name__ == "__main__":
c = Model()
You was trying to insert into db after return in your place_holder method which is not possible because the function exit after return. Also in your sql specify in which column you want to insert into.
like this
self.cursor.execute(f"INSERT INTO main (T_num, Name, Item1, Item2) VALUES {_placeholder}", self.list2)
There is your complete program, hope this will help you.
import tkinter as tk
import sqlite3
class Model():
def __init__(self):
self.list1 = [('Table #', '6'), ('Name', 'Jenn'), ('Beef Tacos', '6'), ("Fish Tacos", "6")]
self.list2 = list(map(": ".join, self.list1))
self.conn = sqlite3.connect("4th.db")
self.cursor = self.conn.cursor()
_placeholder = self.place_holder(self.list2)
# specify here in which column you want to insert the data
self.cursor.execute(f"INSERT INTO main (T_num, Name, Item1, Item2) VALUES {_placeholder}", self.list2)
self.conn.commit()
self.conn.close()
def place_holder(self, input_list):
'''Returns the place holder (?, ?, .....) as string'''
return f"({', '.join('?' * len(input_list))})"
if __name__ == "__main__":
c = Model()

Sorting entries in a ttk treeview automaticly after inserting

Is there a way to achieve a similar result like in this post python ttk treeview sort numbers but without pressing on the heading? Best way would be right after an item is inserted.
If you are going to sort your contents every time you insert a new item, then a more efficient approach would be to insert the item in the right place rather than sorting the whole data for each insertion.
Here's one way to achieve this using the standard bisect module, whose bisect(a, x) function gives you the index at which x should be inserted in a to maintain order (a is assumed to be sorted). In my example below:
my whole interface is stored in some class GUI;
my treeview is called self.tree and features only one column;
my insert_item method inserts a new line below a certain category in the tree (pointed to by location), and items below each category must be sorted separately in my application, which is why I only retrieve that category's children .
from bisect import bisect
# ... class GUI contains the treeview self.tree ...
def insert_item(self, location, item_name, item_id):
"""Inserts a new item below the provided location in the treeview,
maintaining lexicographic order wrt names."""
contents = [
self.tree.item(child)["text"]
for child in self.tree.get_children(location)
]
self.tree.insert(
location, bisect(contents, item_name), item_id, text=item_name
)
To sort the Treeview after each new item insertion, just add an explicit call to the sorting function at the correct position in your code.
Example code:
import tkinter as tk
from tkinter import ttk
counter = 0
numbers = ['1', '10', '11', '2', '3', '4', '24', '12', '5']
def sort_treeview():
content = [(tv.set(child, column), child)
for child in tv.get_children('')]
try:
content.sort(key=lambda t: int(t[0]))
except:
content.sort()
for index, (val, child) in enumerate(content):
tv.move(child, '', index)
def add_item():
global counter
if counter < 8:
tv.insert('', 'end', values=numbers[counter])
counter += 1
# Sort the treeview after the new item was inserted
# -------------------------------------------------
sort_treeview()
root = tk.Tk()
column = 'number'
tv = ttk.Treeview(root, columns=column, show='headings')
tv.pack()
button = tk.Button(root, text='Add entry', command=add_item)
button.pack()
root.mainloop()

How to add columns to a tkinter.Listbox?

I am trying to add these panda columns to a Listbox, so they read like this:
New Zealand NZD
United States USD
ETC.
I am using pandas to get the data from a .csv, but when I try and use a for loop to add the items to the list box using insert I get the error
NameError: name 'END' is not defined or
NameError: name 'end' is not defined
Using this code:
def printCSV():
csv_file = ('testCUR.csv')
df = pd.read_csv(csv_file)
print (df[['COUNTRY','CODE']])
your_list = (df[['COUNTRY','CODE']])
for item in your_list:
listbox.insert(end, item)
You could turn the csv file into a dictionary, use the combined country and currency codes as the keys and just the codes as the values, and finally insert the keys into the Listbox. To get the code of the current selection, you can do this: currencies[listbox.selection_get()].
listbox.selection_get() returns the key which you then use to get the currency code in the currencies dict.
import csv
import tkinter as tk
root = tk.Tk()
currencies = {}
with open('testCUR.csv') as f:
next(f, None) # Skip the header.
reader = csv.reader(f, delimiter=',')
for country, code in reader:
currencies[f'{country} {code}'] = code
listbox = tk.Listbox(root)
for key in currencies:
listbox.insert('end', key)
listbox.grid(row=0, column=0)
listbox.bind('<Key-Return>', lambda event: print(currencies[listbox.selection_get()]))
tk.mainloop()

Python 3x query data using dates from datepicker dialog

One last attempt to solve this problem. I have a Python program that queries the database using a default rundate to today - timedelta(7). I have created a datepicker to be opened using a menu button if the user want to choose their own dates to query. I am having problems figuring out the query that will integrate the dates chosen by the datepicker into the program.
The datepicker works fine as I am able to print the start and end dates that are chosen using
def submit():
start = self.result1.strftime("%m/%d/%Y")
end = self.result2.strftime("%m/%d/%Y")
print(start, end)
I assume that the "print(start, end)" will have to be changed to "return(start,end)" to incorporate it into the main query but I could be wrong.
The initial query and top part of the interface is
import pyodbc
from datetime import date, timedelta
from tkinter import *
from tkinter.ttk import *
import calendar
from decimal import *
import sqlite3
import os
import pick
db = r"M:\CWA_DB\WPTS\WPTS_Prod\WPTS_PROD_be.accdb"
conn = pyodbc.connect('Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq='+db)
cur = conn.cursor()
#Rundate, 7 days ago
rundate = date.today() - timedelta(7)
print(rundate)
#Query permits made effective since rundate
query = '''select `NPDES_ID`, `EffectiveDate`, `FacilityName`, `StateFacilityID`, `City`, `CountyName`
from Permits
where `EffectiveDate` >= ?
order by `NPDES_ID`'''
IDS=[]
FacCodes=[]
PermStrings=[]
PayStrings=[]
OwnerStrings=[]
MTB=[]
MTG=[]
MTR=[]
SWC=[]
MT0=[]
count=0
#for each row in result of query
for row in cur.execute(query, (rundate)):
try:
d= row[1].strftime('%m/%d/%Y')
except:
d=""
#create a display string with the appropriate information permit # - date - facility name - city, county
for i in range(len(row)):
if not row[i]:
row[i] = ""
permitstring=row[0]+" | "+d+"\t | "+row[2]+"\t | "+row[4]+", "+row[5]+" County"
IDS.append(row[0])
tempid=row[0]
#add the index to the appropriate permit type array, used to display seperately
if tempid[0:3]=="MTB":
MTB.append(count)
if tempid[0:3]=="MTG":
MTG.append(count)
if tempid[0:4]=="MTR0":
MTR.append(count)
if tempid[0:3]=="MT0" or tempid[0:3]=="MT4" or tempid[0:3]=="MTX":
MT0.append(count)
if tempid[0:4]=="MTR1":
SWC.append(count)
FacCodes.append(row[3])
PermStrings.append(permitstring)
count+=1
WPTSInv=[]
#get the owners for the permits
for i in range(len(IDS)):
query = '''select `Owner`
from Owners
where `StateFacilityID` = ?'''
for row in cur.execute(query, (str(FacCodes[i]))):
#create an owner name string for the facility ID
OwnerStrings.append("Owner: "+row[0])
#get payments on the permits
for i in range(len(IDS)):
paydate = date.today() - timedelta(60)
query = '''select `AmountPaid_credit`, `PayComment`, `DateReceived`, `WPTSinvoiceNo`
from Payments
where `NPDES_ID` = ? and `DateReceived` >= ?'''
PayStrings.append("\tPayment Received")
for row in cur.execute(query, (IDS[i],paydate)):
WPTSInv.append(row[3])
d= row[2].strftime('%m/%d/%Y')
#create a payment string
PayStrings[i]="\t$"+str(round(Decimal(row[0]),2))+" | "+d+" | "+row[1]
#Initiate interface
root = Tk()
master = Frame(root, name='master')
master.pack(fill=BOTH)
root.geometry("800x800+300+100")
root.title('WeeklyReport')
menu_bar = Menu(root)
def exit():
root.destroy()
def GetCalendar():
os.system("Pick.py")
root.wait_window
filemenu = Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="File", menu=filemenu)
filemenu.add_command(label="Exit", command=exit)
datemenu = Menu(menu_bar)
menu_bar.add_command(label='Change Date', command=GetCalendar)
root.config(menu=menu_bar)
# start the app
if __name__ == "__main__":
master.mainloop()
I have searched high and low for a solution but have not had much luck. I am sure others would be helped by an answer (even if the answer is that what I am trying to do is impossible)

Python output is blank when i execute the following code:

This program is a banking system. It connects to an online database which contains customer details and transaction details. However, when I execute the code, I get a blank output in python 3.4.0 shell:
import pyodbc
cnxn = pyodbc.connect('Driver={SQL Server};'
'Server=***;'
'Database=***;'
'uid=***;pwd=***')
cursor = cnxn.cursor()
def MainMenu():
print('##############################\n\tWelcome to the XYZ Banking System\n##############################')
print()
print('PLEASE ENTER THE NUMBER CORRESPONDING TO YOUR DESIRED COMMAND IN THE PROMPT BELOW : \n\t1.ACCESS CUSTOMER DETAILS\n\t2.ACCESS TRANSACTION PORTAL\n##############################')
print()
var_UserInput=input('>>>')
if var_UserInput=='1':
return CustomerPortal()
def CustomerPortal():
cursor.tables()
rows = cursor.fetchall()
for row in rows:
print (row.customer)
MainMenu()
Try this. I've made a few changes:
Moved the connection string into the function
Modified the code to be closer to PEP-8 https://www.python.org/dev/peps/pep-0008/
Fixed indentation
Here's the code.
import pyodbc
def main_menu():
print('##############################\n\tWelcome to the XYZ Banking System\n##############################')
print()
print('PLEASE ENTER THE NUMBER CORRESPONDING TO YOUR DESIRED COMMAND IN THE PROMPT BELOW : \n\t1.ACCESS CUSTOMER DETAILS\n\t2.ACCESS TRANSACTION PORTAL\n##############################')
print()
var_user_input=input('>>>')
if var_user_input=='1':
return customer_portal()
def customer_portal():
cnxn = pyodbc.connect('Driver={SQL Server};'
'Server=***;'
'Database=***;'
'uid=***;pwd=***')
cursor = cnxn.cursor()
cursor.tables()
rows = cursor.fetchall()
for row in rows:
print (row.customer)
cursor.close()
if __name__ == "__main__":
main_menu()
Good luck!

Resources