Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import re
- from tkinter import *
- from tkinter.ttk import *
- import pymysql.cursors
- class DBTest:
- #Initiates thingies we'll use
- def __init__(self, root):
- self._create_tabs()
- self._layout()
- def _create_tabs(self):
- self.frame = Frame(root) # Main Frame
- self.nb = Notebook(self.frame) # The 'tab-thingy'
- # Create main tabs
- customer = Frame(self.nb)
- order = Frame(self.nb)
- product = Frame(self.nb)
- # Create customer NB
- self.customer = Notebook(customer)
- # Create Customer-tabs
- customer.insert = Frame(self.customer)
- customer.select = Frame(self.customer)
- customer.selAll = Frame(self.customer)
- customer.delete = Frame(self.customer)
- self._customer_insert_frame(customer.insert)
- self._customer_select_frame(customer.select)
- self._customer_selAll_frame(customer.selAll)
- self._customer_delete_frame(customer.delete)
- # Create order NB
- self.order = Notebook(order)
- # Create order-tabs
- order.insert = Frame(self.order)
- order.select = Frame(self.order)
- order.selAll = Frame(self.order)
- self._order_insert_frame(order.insert)
- #self._order_select_frame(order.select)
- #self._order_selAll_frame(order.selAll)
- # Adds the tabs to the notebook
- self.nb.add(customer, text="Customer")
- self.nb.add(order, text="Order")
- self.nb.add(product, text="Product")
- self.customer.add(customer.insert, text="Insert")
- self.customer.add(customer.select, text="Select")
- self.customer.add(customer.selAll, text="Select ALL")
- self.customer.add(customer.delete, text="Delete Cust.")
- self.order.add(order.insert, text="Insert")
- self.order.add(order.select, text="Select")
- self.order.add(order.selAll, text="Select ALL")
- def _layout(self):
- # Layout
- self.frame.grid(row=0, column=0, sticky=(N,S,W,E))
- self.nb.grid(row=0, column=0, sticky=(N,S,W,E))
- self.customer.grid(row=0, column=0, columnspan=2, sticky=(N,S,W,E), pady=5)
- self.order.grid(row=0, column=0, columnspan=2, sticky=(N,S,W,E), pady=5)
- # Resize rules
- root.columnconfigure(0, weight=1)
- root.rowconfigure(0, weight=1)
- self.frame.columnconfigure(0, weight=2)
- self.frame.rowconfigure(0, weight=2)
- def _customer_insert_frame(self, insert):
- # Creates the Entry boxes to get data
- insert.name = Entry(insert)
- insert.address = Entry(insert)
- insert.phone = Entry(insert)
- # Makes a label and puts things out on the screen.
- Label(insert, text="Name: ").grid(row=0, column=0, sticky=E)
- insert.name.grid(row=0, column=1, sticky=W)
- Label(insert, text="Address: ").grid(row=1, column=0, sticky=E)
- insert.address.grid(row=1, column=1, sticky=W)
- Label(insert, text="Phone: ").grid(row=2, column=0, sticky=E)
- insert.phone.grid(row=2, column=1, sticky=W)
- # Using 'lambda: ' to prevent prepare_insert from running before we want it to.
- insert.submit_button = Button(insert, text="Submit", command=lambda: self.customer_prepare_insert(insert))
- insert.submit_button.grid(row=4, column=0, columnspan=2)
- insert.text = Text(insert, width=30, height=4, wrap=WORD)
- insert.text.grid(row=5,column=0,columnspan=2)
- def customer_prepare_insert(self, insert):
- """ Reg ex for the phone number.
- Explanation:
- [+]? = First char can be a +, not needed tho
- [\d -]* = allow unlimited digits (0-9), spaces and -
- {3,} = Specifies at least 3 numbers."""
- pattern = re.compile(r"^[+]?[\d -]{3,}")
- # Gets values from the Entry boxes above.
- name = insert.name.get()
- address = insert.address.get()
- phone = insert.phone.get()
- # Checks if every field has something in them. (Does not check if only a space)
- if not all((name, address, phone)):
- errorText = "Need to enter something in all boxes."
- error = True
- # Checks if the phone-pattern matches our regEx
- elif not pattern.match(phone):
- error = True
- errorText = "Phone number can only contain 0-9, spaces and dashes (-).\nFirst symbol can be + for country codes."
- else:
- error = False
- # If we have an error, throw the error text
- if error:
- text = errorText
- # Else does the insert into DB.
- else:
- text = self.add_to_DB('CUSTOMER',name, address, phone)
- insert.text.config(state=NORMAL)
- insert.text.delete(0.0, END)
- insert.text.insert(0.0, text)
- insert.text.config(state=DISABLED)
- def _customer_select_frame(self, select):
- # Create the Entry boxes
- select.sID = Entry(select)
- select.name = Entry(select)
- select.address = Entry(select)
- select.phone = Entry(select)
- # Puts them out on the frame
- Label(select, text="Search for Databasedata\nenter at least 1 searchfield").grid(row=0, column=0, columnspan=2)
- Label(select, text="Search ID:").grid(row=1, column=0, sticky=E)
- select.sID.grid(row=1, column=1, sticky=W)
- Label(select, text="Search Name:").grid(row=2, column=0, sticky=E)
- select.name.grid(row=2, column=1, sticky=W)
- Label(select, text="Search address").grid(row=3, column=0, sticky=E)
- select.address.grid(row=3, column=1, sticky=W)
- Label(select, text="Search phone").grid(row=4, column=0, sticky=E)
- select.phone.grid(row=4, column=1, sticky=W)
- # Using lambda again on the button to not make it do the
- # prepare before we actually click the button
- select.submit_button = Button(select, text="Submit", command=lambda: self.customer_prepare_select(select))
- select.submit_button.grid(row=5, column=0, columnspan=2)
- select.text = Text(select, width=30, height=10, wrap=WORD)
- select.text.grid(row=6,column=0,columnspan=2)
- def customer_prepare_select(self, select):
- # Get value from the search fields.
- sID = select.sID.get()
- name = select.name.get()
- address = select.address.get()
- phone = select.phone.get()
- args = {}
- stmt = ""
- # Checks at least one have data. (Does not check if only a space)
- if sID != "" or name != "" or address != "" or phone != "":
- # If at least one have data we check which
- # one and adds the string for the query
- if sID != "":
- args['ID'] = "id='"+sID+"' AND "
- if name != "":
- args['name'] = "name='"+name+"' AND "
- if address != "":
- args['address'] = "address='"+address+"' AND "
- if phone != "":
- args['phone'] = "phone='"+phone+"'"
- for key, value in args.items():
- stmt += value
- # Removes the last ' AND '
- stmt = stmt[:-5]
- sql = "SELECT * FROM CUSTOMER WHERE {val}".format(val=stmt)
- db_result = self.get_from_DB(sql)
- textBox = ""
- # If we get rows back
- if db_result:
- # Iterates for all rows gotten
- for key in db_result:
- textBox += "ID: {id} Name: {name}\nAddress: {address}\nPhone: {phone}\n\n".format(id=key['id'], name=key['name'], address=key['address'], phone=key['phone'])
- # If we searched for an entry that didnt exist
- else:
- textBox = "Could not find what you searched for."
- # If we enter no value in any box.
- else:
- textBox = "Must insert at least one value."
- # Updates the textfield
- select.text.config(state=NORMAL)
- select.text.delete(0.0, END)
- select.text.insert(0.0, textBox)
- select.text.config(state=DISABLED)
- def _customer_selAll_frame(self, selAll):
- #Create the button to show everything
- Label(selAll, text="Fetch all entries?").grid(row=0, column=0, sticky=E)
- selAll.submit_button = Button(selAll, text="Fetch!", command=lambda: self.customer_select_all_DB(selAll))
- selAll.submit_button.grid(row=0, column=1, sticky=W)
- selAll.text = Text(selAll, width=30, height=15, wrap=WORD)
- selAll.text.grid(row=1, column=0, columnspan=2)
- def customer_select_all_DB(self, selAll):
- sql = "SELECT * from CUSTOMER"
- # Gets all entries from the DB
- db_result = self.get_from_DB(sql)
- textBox = ""
- # If we get result returned
- if db_result:
- # Iterates for every Row
- for key in db_result:
- textBox += "ID: {id} Name: {name}\nAddress: {address}\nPhone: {phone}\n\n".format(id=key['id'], name=key['name'], address=key['address'], phone=key['phone'])
- # If no entries was found in the DB
- else:
- textBox = "There's nothing in the Database or some error n shit."
- # Updates the textfield
- selAll.text.config(state=NORMAL)
- selAll.text.delete(0.0, END)
- selAll.text.insert(0.0, textBox)
- selAll.text.config(state=DISABLED)
- def _customer_delete_frame(self, delete):
- Label(delete, text="Delete a user with the dropdown menu").grid(row=0, column=0, columnspan=2, sticky=E)
- # Creates the menu
- # The variable we need to "get"-value from
- delete.var = StringVar()
- delete.var.set("None")
- # Gets the list with usernames:
- delete.users = self.get_customer_list()
- delete.menu = OptionMenu(delete, delete.var, *delete.users[0])
- delete.menu.grid(row=1, column=0)
- delete.submit_button = Button(delete, text="DELETE!", command=lambda: self.customer_delete_from_DB(delete))
- delete.submit_button.grid(row=2)
- delete.update_button = Button(delete, text="\"Update\" List", command=lambda: self.rebuild_window())
- delete.update_button.grid(row=4)
- delete.text = Text(delete, width=30, height=15, wrap=WORD)
- delete.text.grid(row=3, column=0, columnspan=2)
- def customer_delete_from_DB(self, delete):
- # Gets the name we want to delete
- # and sets from which tab(table) and column
- custName = delete.var.get()
- custID = delete.users[1].get(custName)
- table = "customer"
- x = self.delete_from_DB(table, custID, custName)
- delete.text.config(state=NORMAL)
- delete.text.delete(0.0, END)
- delete.text.insert(0.0, x)
- delete.text.config(state=DISABLED)
- def _order_insert_frame(self, insert):
- # Makes the Customer and Product Frames
- self.order_customer = LabelFrame(insert, text="Buyer: ", labelanchor=N)
- self.order_customer.grid(row=0, column=0, sticky=(N,S,W,E))
- self.order_product = LabelFrame(insert, text="Product: ",labelanchor=N)
- self.order_product.grid(row=1, column=0, sticky=(N,S,W,E))
- self.order_amount = LabelFrame(insert, text="Amount: ", labelanchor=N)
- self.order_amount.grid(row=2, column=0, sticky=(N,S,W,E))
- self.order_confirm = LabelFrame(insert, text="Confirm: ",labelanchor=N)
- self.order_confirm.grid(row=3, column=0, sticky=(N,S,W,E))
- # Some default Vars
- insert.productVar = StringVar()
- insert.productVar.set("None")
- insert.totalUnits = IntVar()
- insert.customerVar = StringVar()
- insert.customerVar.set("None")
- # Gets the list of customers
- insert.customers = self.get_customer_list()
- insert.customerMenu = OptionMenu(self.order_customer, insert.customerVar, *insert.customers[0])
- insert.customerMenu.grid(row=0, column=1, sticky=EW)
- # Gets the list of products and current stocks
- insert.products = self.get_product_list()
- insert.unitLabel = Label(self.order_product, text="In stock: ~")
- insert.unitLabel.grid(row=0, column=1, sticky=W)
- insert.productMenu = OptionMenu(self.order_product, insert.productVar, *insert.products[0], command=lambda _: self.order_update_price(insert))
- insert.productMenu.config(width=15)
- insert.productMenu.grid(row=0, column=0, sticky="EW")
- # Enter how many you want to buy
- insert.amount = Entry(self.order_amount)
- insert.amount.grid()
- insert.insert_button = Button(self.order_confirm, text="Submit", command=lambda: self.order_prepare_insert(insert))
- insert.insert_button.grid(row=0, column=0)
- # Shows result.
- insert.text = Text(self.order_confirm, width=30, height=10, wrap=WORD)
- insert.text.grid(row=1, column=0,columnspan=2, sticky=(N,S,W,E))
- insert.text.config(state=DISABLED)
- def order_prepare_insert(self, x):
- # Only allow numbers
- pattern = re.compile(r"^[^0][\d]{1,}")
- # Sets up the things we need to use
- error = False
- errorT = ""
- totUnit = x.totalUnits.get()
- amount = x.amount.get()
- cust = x.customerVar.get()
- custID = x.customers[1].get(cust, "CustError")
- prod = x.productVar.get()
- prodID = x.products[1].get(prod, "prodError")
- # Try and see if amount is a number
- try:
- amount = int(amount)
- except Exception:
- error = True
- # Checks so everything is entered:
- if cust == "None" or prod == "None":
- error = True
- errorT = "Must choose a customer and/or product.\n"
- # If amount doesn't match pattern
- if not pattern.match(str(amount)):
- error = True
- errorT += "Amount must contain numbers (0-9), can't be 0\n"
- # Checks if we don't have an error
- if not error:
- if int(totUnit) - amount < 0:
- answer = "Can't order more units than what exist in stock."
- else:
- stock = int(totUnit) - int(amount)
- answer = "Customer: {cust} with ID: {custid}\nOrdered: {amount} units\nProduct: {prod} with ID: {prodID}\nUnits left: {stock}".format(cust=cust, custid=custID, prod=prod, prodID=prodID, amount=amount, stock=stock)
- else:
- answer = errorT
- x.text.config(state=NORMAL)
- x.text.delete(0.0, END)
- x.text.insert(0.0, answer)
- x.text.config(state=DISABLED)
- def order_update_price(self, insert):
- productName = insert.productVar
- unitsList = insert.products[2]
- errorT = False
- if productName.get() != "None":
- units = unitsList[productName.get()]
- else:
- units = 0
- try:
- insert.totalUnits.set(int(units))
- except Exception as e:
- errorT = True
- error = self.errorCodeHandler(e)
- if errorT:
- text = error
- else:
- text = "In stock: "+str(units)
- insert.unitLabel.config(text=text)
- def delete_from_DB(self, table, value, *args):
- # Making the query
- # Takes the tab (order, customer, products), plus the ID of the thing to delete
- # This is to re-use this delete code for other tabs.
- sql = "DELETE FROM {tab} WHERE id='{value}'".format(tab=table.upper(), value=value)
- # Connection config
- connection = self.db_settings()
- # Try to do the thing
- try:
- with connection.cursor() as cursor:
- # Executes the delete-query
- cursor.execute(sql)
- #Commit the changes
- connection.commit()
- # Checks how many rows that was affected
- result = cursor.rowcount
- # If 1 (row deleted) then show message.
- if result == 1:
- if args[0]:
- result = "{name} from {tab}-tab has been deleted from the Database.\n".format(name=args[0], tab=table)
- else:
- result = "The order with the ID: {id} was succesfully deleted.".format(id=value)
- # If 0, no rows affected, thus nothing deleted.
- elif result == 0:
- result = "Nothing got deleted."
- else:
- result = "Something weird happened. More than 1 row changed."
- except Exception as e:
- result = self.errorCodeHandler(e)
- finally:
- connection.close()
- # Return value
- return result
- def add_to_DB(self, *args):
- """
- Accepts multiple args depending on what for.
- If args[0] is equal to, it wants these values:
- CUSTOMER: name, address, phone
- ORDER: customer_id, product_id, amount
- PRODUCT: name, unit (in stock), price (per unit)
- """
- # Connection config
- connection = self.db_settings()
- #Inserting the data
- try:
- # Adds it to DB
- with connection.cursor() as cursor:
- if args[0] == 'CUSTOMER':
- # Makes query for CUSTOMER
- # Args needed are args[1-3], name, address, phone.
- sql = "INSERT INTO CUSTOMER (name, address, phone) VALUES (%s, %s, %s)"
- cursor.execute(sql, (args[1], args[2], args[3]))
- result = "Data added\nName: {name}\nAddress: {address}\nPhone: {phone}".format(name=args[1],address=args[2],phone=args[3])
- elif args[0] == 'ORDERS':
- # Makes query for ORDERS
- # Args needed are args[1-3], customer_id, product_id, amount
- cursor.execute("INSERT INTO ORDERS (customer_id, product_id, amount) VALUES (%d, %d, %d)", [args[1], args[2], args[3]])
- result = "Data added\nCustomer ID: {custID}\nProduct ID: {prodID}\nAmount: {amount} ex.".format(custID=args[1], prodID=args[2], amount=args[3])
- elif args[0] == 'PRODUCT':
- # Makes query for PRODUCT
- # Args needed are args[1-3], name, unit, price
- cursor.execute("INSERT INTO PRODUCT (name, unit, price) VALUES (%s, %d, %d", [args[1], args[2], args[3]])
- result = "Data added\nProduct: {name}\nUnits: {unit} ex.\nPrice: {price}€ each".format(name=args[1], unit=args[2], price=args[3])
- # Comit the query
- connection.commit()
- except Exception as e:
- result = self.errorCodeHandler(e)
- finally:
- connection.close()
- # Returns whatever result we got
- return result
- def get_from_DB(self, sql):
- # Connection config
- connection = self.db_settings()
- # Try to get data
- try:
- with connection.cursor() as cursor:
- # The query from prepare_select()
- cursor.execute(sql)
- result = cursor.fetchall()
- except Exception as e:
- result = self.errorCodeHandler(e)
- finally:
- connection.close()
- return result
- """Returns:
- # [0] = list with only names
- # [1] = dictionary name : id
- """
- def get_customer_list(self, *args):
- sql = "SELECT name, id FROM CUSTOMER"
- # Gets all customers and put them in a list
- users = self.get_from_DB(sql)
- user = []
- userID = {}
- # Iterates the Dict we got, and turns them into list with just names.
- if users:
- for key in users:
- user.append(key['name'])
- userID[key['name']] = key['id']
- # Alphabetical sorting, cuz why not
- user.sort()
- # Adds "None" to start of list, cuz else OptionMenu gets wonky
- user.insert(0, "None")
- return user, userID
- """Returns
- # [0] = list with only names
- # [1] = dictionary, name : id
- # [2] = dictionary, name : units
- """
- def get_product_list(self, *args):
- sql = "SELECT name, id, unit FROM PRODUCT"
- # Gets all products and their ID and puts them in a list
- db_products = self.get_from_DB(sql)
- db_product = []
- db_productID = {}
- db_productAmount = {}
- # Iterates through the dictionary we get back from DB
- if db_products:
- for key in db_products:
- db_product.append(key['name'])
- db_productID[key['name']] = key['id']
- db_productAmount[key['name']] = key['unit']
- # Alphabetical sorting, cuz why not
- db_product.sort()
- # Adds "None" to start of list, avoiding wonkyness
- db_product.insert(0, "None")
- return db_product, db_productID, db_productAmount
- # Destroys all windows, and rebuilds.
- # Got tired of trying other ways.
- def rebuild_window(self):
- self.frame.destroy()
- self._create_tabs()
- self._layout()
- def errorCodeHandler(self, error):
- # Simple "One place for all error codes"-thingy.
- return {
- 1062 : "Dublicate entry was found!",
- 1451 : "Entry is tied to a foreign key (orders)\nCan't be deleted until the order tied to this entry is deleted."
- }.get(error.args[0], "Something weird happened, give this errorcode to someone more handy: "+str(error.args[0]) +"\n\nFor debug use:\n"+str(error))
- ##########
- #The settings for the database, change this.
- ##########
- def db_settings(self):
- connection = pymysql.connect(host='',
- user='',
- password='',
- db='',
- charset='utf8',
- cursorclass=pymysql.cursors.DictCursor)
- return connection
- root = Tk()
- # Makes window not resizeable.
- root.resizable(0,0)
- # Window size
- root.geometry("260x390")
- # Title on the window
- root.title("GUI Test :>")
- # "activates"(words pls) the mainClass
- app = DBTest(root)
- # Main loop for the tkinder
- root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement