Eel is a little Python library for making simple Electron-like offline HTML/JS GUI apps, with full access to Python capabilities and libraries.
https://github.com/ChrisKnott/Eel
Install
pip install eel
C:\python_dev\crud>pip install eel
Install PyAutoGUI
https://pypi.org/project/PyAutoGUI/
pip install PyAutoGUI
C:\python_dev\crud>pip install PyAutoGUI
Create Database sqlite3 using python
createdb.py
//createdb.py import sqlite3 from sqlite3 import Error def create_connection(db_file): """ create a database connection to a SQLite database """ conn = None try: conn = sqlite3.connect(db_file) print(sqlite3.version) except Error as e: print(e) finally: if conn: conn.close() if __name__ == '__main__': create_connection(r"C:\python_dev\crud\views\database\storage.db")run
C:\python_dev\crud>python createdb.py
Create Database Table
CREATE TABLE tblemployee (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR (150),
position VARCHAR (150),
office VARCHAR (150)
);
main.py
#main.py import eel from views.models.employee import showallrecords, save_newemployee, show_selectedEmployee, update_newemployee, show_deleteEmployee import pyautogui #https://pypi.org/project/PyAutoGUI/ eel.init('views') @eel.expose def fetchalldata(): select_reg = showallrecords() eel.action_out(select_reg) @eel.expose def btn_save(name, position, office): msg = save_newemployee(name, position, office) eel.save_return(str(msg)) @eel.expose def get_employee(id): select_employee = show_selectedEmployee(id) eel.action_edit(select_employee) @eel.expose def btn_update(name, position, office, id): msg = update_newemployee(name, position, office, id) eel.update_return(str(msg)) @eel.expose def get_delete_employee(id): select_del_employee = show_deleteEmployee(id) eel.delete_return(select_del_employee) eel.start( 'templates/index.html', size=pyautogui.size() )employee.py
#employee.py import sqlite3 def showallrecords(): try: connect = sqlite3.connect("views/database/storage.db") cursor = connect.cursor() cursor.execute("SELECT * FROM tblemployee") registers = [] for item in cursor.fetchall(): #test = item[1] #print(test) registers.append(item) return registers except Exception as error: print(error) msg = "Error" return msg def save_newemployee(name, position, office): try: connect = sqlite3.connect("views/database/storage.db") cursor = connect.cursor() if name != "" and position != "" and office != "": cursor.execute("INSERT INTO tblemployee(name, position, office) VALUES(?,?,?)",(name, position, office)) connect.commit() connect.close() msg = "success" return msg else: msg = "failure" return msg except Exception as Error: print(Error) msg = "failure" return msg def show_selectedEmployee(id): try: connect = sqlite3.connect("views/database/storage.db") cursor = connect.cursor() cursor.execute("SELECT * FROM tblemployee WHERE id =?", (id,)) editemployees = [] for item in cursor.fetchone(): editemployees.append(item) return editemployees except Exception as error: print(error) msg = "Error" return msg def update_newemployee(name, position, office, id): try: connect = sqlite3.connect("views/database/storage.db") cursor = connect.cursor() if name != "" and position != "" and office != "": cursor.execute("UPDATE tblemployee SET name =?, position =?, office =? WHERE id =?", (name, position, office, id,)) connect.commit() connect.close() msg = "success" return msg else: msg = "failure" return msg except Exception as Error: print(Error) msg = "failure" return msg def show_deleteEmployee(id): try: connect = sqlite3.connect("views/database/storage.db") cursor = connect.cursor() cursor.execute("DELETE FROM tblemployee WHERE id =?", (id,)) connect.commit() connect.close() msg = "success" return msg except Exception as error: print(error) msg = "Error" return msgMake your Front-end HTML CSS and Javascript
crud\views\templates\index.html
//crud\views\templates\index.html <!DOCTYPE html> <html lang="pt-br"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script type="text/javascript" src="/eel.js"></script> <link rel="stylesheet" href="../css/index.css"> <link rel="icon" href="../img/myglogo.png"> <title>Python Desktop App CRUD (Create Read Update and Delete ) sqlite3 using python eel</title> </head> <body> <div class="container"> <p style="text-align:center;"><h2>Python Desktop App CRUD (Create Read Update and Delete ) sqlite3 using python eel</h2></p> <p style="text-align:right;"><button type="button" class="btn" id="btn_addnew">Add New</button></p> <table id="employeedatatable" class="styled-table"> <tr> <th>ID</th> <th>Name</th> <th>Position</th> <th>Office</th> <th>Action</th> </tr> </table> <div class="modalContainer" id="Addnewmodal"> <div class="modal-content"> <span id="close" class="close">×</span> <p style="text-align:center;"><h2>Add New Employee</h2></p> <form class="form-detail" action="#" method="post" id="myform"> <div class="form-row"> <label>Full Name:</label> <input type="text" name="txtfullname" id="txtfullname" class="input-text" required placeholder="ex: Cairocoders Ednalan"> </div> <div class="form-row"> <label>Position:</label> <input type="text" name="txtposition" id="txtposition" class="input-text" required> </div> <div class="form-row"> <label>Office:</label> <input type="text" name="txtoffice" id="txtoffice" class="input-text" required> </div> <div class="form-row-last"> <input type="submit" name="register" class="button" value="Add New Employee" onclick="save_register_js();"> </div> <div class="box"><label class="label_input" id="return_register" style="width: 90%;color:green;font-weight:bold;"></label></div> </form> </div> </div> <div class="modalContainer" id="Edit_modal"> <div class="modal-content"> <span id="close" class="closeedit">×</span> <p style="text-align:center;"><h2>Edit Employee</h2></p> <form class="form-detail" action="#" method="post" id="myformedit"><input type="hidden" name="id" id="id"> <div class="form-row"> <label>Full Name:</label> <input type="text" name="edit_name" id="edit_name" class="input-text" required> </div> <div class="form-row"> <label>Position:</label> <input type="text" name="edit_position" id="edit_position" class="input-text" required> </div> <div class="form-row"> <label>Office:</label> <input type="text" name="edit_office" id="edit_office" class="input-text" required> </div> <div class="form-row-last"> <input type="submit" name="register" class="button" value="Update" onclick="save_edit();"> </div> <div class="box"><label class="label_input" id="return_update" style="width: 90%;color:green;font-weight:bold;"></label></div> </form> </div> </div> <div class="modalContainer" id="Delete_modal"> <div class="modal-content"> <span id="close" class="closedelete">×</span> <p style="text-align:center;"><h2>Delete Employee</h2></p> <p style="text-align:center;"><h3>Are you sure you want to delete this data?</h3></p> <div class="form-detail"> <input type="hidden" name="idvalue" id="idvalue"> <input type="submit" name="btndelete" class="button" value="Delete" onclick="btn_submitdelete($('#idvalue').val());"> <div class="box"><label class="label_input" id="return_delete" style="width: 90%;color:green;font-weight:bold;"></label></div> </div> </div> </div> </div> <script type="text/javascript" src="../js/jquery.min.js"></script> <script type="text/javascript" src="../js/jquery.validate.min.js"></script> <script type="text/javascript" src="../js/main.js"></script> </body> </html>crud\views\js\main.js
#crud\views\js\main.js $(document).ready(function(){ eel.fetchalldata() $("#btn_addnew").on("click", function() { $("#Addnewmodal").show(); }); $(".close").on("click", function() { $("#Addnewmodal").hide(); }); $(".closeedit").on("click", function() { $("#Edit_modal").hide(); }); $(".closedelete").on("click", function() { $("#Delete_modal").hide(); }); }) function link(target) { window.location.href=target; } eel.expose(action_out) function action_out(registers){ //alert("Show Table"); registers.forEach(showdata) } eel.expose(action_edit) function action_edit(editemployees){ //alert(editemployees); editemployees.forEach(get_array_values) } function get_array_values(item, index){ //alert(item); //alert(index); if (index == 0) { document.getElementById("id").value = item; } else if (index == 1) { document.getElementById("edit_name").value = item; } else if (index == 2) { document.getElementById("edit_position").value = item; } else if (index == 3) { document.getElementById("edit_office").value = item; } else {} } // SAVE async function save_edit(){ $( "#myformedit" ).validate({ messages: { edit_name: { required: "Please provide Name" }, edit_position: { required: "Please provide Position" }, edit_office: { required: "Please provide Office" }, }, submitHandler: function(form) { eel.btn_update($('#edit_name').val(),$('#edit_position').val(),$('#edit_office').val(),$('#id').val()) //alert("Success"); } }); } function showdata(item, index){ var get_table = document.getElementById("employeedatatable"); var tr = document.createElement("tr"); var td = document.createElement("td"); var td2 = document.createElement("td"); var td3 = document.createElement("td"); var td4 = document.createElement("td"); var td5 = document.createElement("td"); var id = item[0] td.innerText = item[0] td2.innerText = item[1] td3.innerText = item[2] td4.innerText = item[3] td5.innerHTML = '<button type="button" class="btn" onclick="btn_edit('+ id +')">Edit</button> | <button type="button" class="btndelete" onclick="buttondelete(('+ id +'))">Delete</button>' get_table.appendChild(tr) tr.appendChild(td) tr.appendChild(td2) tr.appendChild(td3) tr.appendChild(td4) tr.appendChild(td5) } // NEW Employee async function save_register_js(){ $( "#myform" ).validate({ messages: { txtfullname: { required: "Please provide Name" }, txtposition: { required: "Please provide Position" }, txtoffice: { required: "Please provide Office" }, }, submitHandler: function(form) { eel.btn_save($('#txtfullname').val(),$('#txtposition').val(),$('#txtoffice').val()) } }); }; eel.expose(save_return); function save_return(status){ if (status == "success"){ $('#return_register').text('New Employee completed successfully!'); $('#txtfullname').val(''); $('#txtposition').val(''); $('#txtoffice').val(''); } if (status == "failure"){ $('#return_register').text('Error when registering, make sure you have no blank fields.'); } }; eel.expose(edit_return); function edit_return(status){ if (status == "success"){ $('#return_register').text('Employee Updated successfully!'); } if (status == "failure"){ $('#return_register').text('Error when updating, make sure you have no blank fields.'); } }; function buttondelete(id) { document.getElementById("idvalue").value = id; $("#Delete_modal").show(); } async function btn_edit(id){ eel.get_employee(id) $("#Edit_modal").show(); } async function btn_submitdelete(id){ //alert(id); eel.get_delete_employee(id) } eel.expose(update_return); function update_return(status){ if (status == "success"){ $('#return_update').text('Employee Updated successfully!'); $('#txtfullname').val(''); $('#txtposition').val(''); $('#txtoffice').val(''); } if (status == "failure"){ $('#return_update').text('Error when updating record, make sure you have no blank fields.'); } }; eel.expose(delete_return) function delete_return(delemployees){ alert(delemployees); if (status == "success"){ location.href = "index.html"; } if (status == "failure"){ $('#return_delete').text('Error deleting record'); } }crud\views\css\index.css
//crud\views\css\index.css body { color: #162D5D; font-family: 'Roboto', sans-serif; } .container {margin:30px;} .styled-table { border-collapse: collapse;width:100%; margin: 25px 0; font-size: 0.9em; font-family: sans-serif; min-width: 400px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.15); } .styled-table thead tr { background-color: #009879; color: #ffffff; text-align: left; } .styled-table th, .styled-table td { padding: 12px 15px; } .styled-table tr { border-bottom: 1px solid #dddddd; } .styled-table tr:nth-of-type(even) { background-color: #f3f3f3; } .styled-table tr:last-of-type { border-bottom: 2px solid #009879; } .btn { background-color: #04AA6D!important; border-radius: 5px;color:#ffffff; font-size: 17px; font-family: 'Source Sans Pro', sans-serif; padding: 6px 18px; } .btndelete { background-color: #cf2e2e!important; border-radius: 5px;color:#ffffff; font-size: 17px; font-family: 'Source Sans Pro', sans-serif; padding: 6px 18px; } .form-detail .form-row label.error { color: red; } .form-detail .input-text { margin-bottom: 27px; } .form-detail input { width: 91%; padding: 14.5px 15px; border: 1px solid #e5e5e5; border-radius: 5px; -o-border-radius: 5px; -ms-border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; appearance: unset; -moz-appearance: unset; -webkit-appearance: unset; -o-appearance: unset; -ms-appearance: unset; outline: none; -moz-outline: none; -webkit-outline: none; -o-outline: none; -ms-outline: none; font-family: 'Roboto', sans-serif; font-size: 16px; color: #333; } .form-detail .form-row input:focus { border: 1px solid #53c83c; } .form-detail .button { background: #3b63ca; border-radius: 6px; -o-border-radius: 6px; -ms-border-radius: 6px; -moz-border-radius: 6px; -webkit-border-radius: 6px; width: 160px; border: none; margin: 6px 0 50px 0px; cursor: pointer; font-family: 'Roboto', sans-serif; color: #fff; font-weight: 500; font-size: 16px; } .form-detail .button:hover { background: #3356b0; } .modalContainer { display: none; position: fixed; z-index: 1; left: 0; top: 0; width: 100%; height: 100%; background-color: rgb(0, 0, 0); background-color: rgba(0, 0, 0, 0.4); } .modal-content { background-color: #fefefe; margin: 15% auto; padding: 20px; border: 1px solid #888; width: 40%; } #close { color: #aaa; float: right; font-size: 28px; font-weight: bold; cursor: pointer; }Jquery
https://jquery.com/download/
CDN : jsDelivr CDN
https://www.jsdelivr.com/package/npm/jquery
https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js
jQuery Validation
http://jqueryvalidation.org/
Run : C:\python_dev\crud>python main.py