原文链接:【KWDB 创作者计划】_用 Python 与 KWDB 打造智能自动售卖机:从搭建到实践-CSDN博客
作者:大师兄6668
在开发技术不断革新的当下,将Python的灵活编程能力与KWDB强大的数据管理性能相结合,能创造出功能丰富且高效的应用程序。本文将带领大家利用这两者打造一个自动售卖机系统,从环境搭建、功能实现到最终优化,逐步揭开项目的神秘面纱。
在前三篇博文中,我们已经成功在 Centos 云服务中通过 Docker 安装了 KWDB(在 CentOS 云服务中通过 Docker 安装 KWDB数据库),并且掌握了在云服务器上直接连接 KWDB 进行增删改查的操作方法(【云服务器连接已部署 KWDB 并进行增删改查操作】完整指南),而且深入探索如何通过 Python 语言连接 KWDB(【通过 Python 连接 KWDB 数据库】的完整步骤与示例)。
接下来,我们利用这些知识,直接做一个简单的项目——《智能自动售卖机》,我们借助 Python 丰富的生态库,进一步来拓展 KWDB 在数据处理和应用开发方面的能力。
Python作为项目的核心开发语言,可从Python官方网站下载安装包进行安装。建议安装最新稳定版本,以获取更好的性能和功能支持。安装过程中,记得勾选“Add Python to PATH”选项,方便后续在命令行中直接调用Python。
若KWDB尚未安装,可通过Docker进行快速部署。以Centos云服务为例,先确保已安装Docker,接着拉取KWDB镜像:docker pull kwdb/kwdb:latest。之后创建docker-compose.yml文件,配置容器参数:
version: '3.3' services: kaiwudb-container: image: "kwdb/kwdb:latest" container_name: kaiwudb-experience hostname: kaiwudb-experience ports: - 8080:8080 - 26257:26257 ulimits: memlock: -1 volumes: - /dev:/dev networks: - default restart: on-failure ipc: shareable privileged: true environment: - LD_LIBRARY_PATH=/kaiwudb/lib tty: true working_dir: /kaiwudb/bin command: - /bin/bash - -c - | /kaiwudb/bin/kwbase start-single-node --insecure --listen-addr=0.0.0.0:26257 --advertise-addr=127.0.0.1:26257 --http-addr=0.0.0.0:8080 --store=/kaiwudb/deploy/kaiwudb
保存文件后,在所在目录执行docker-compose up -d启动KWDB服务。
项目中需使用psycopg库连接KWDB,通过pip进行安装:pip install "psycopg[binary]"。若涉及Web开发,还可安装Flask框架:pip install flask,方便构建售卖机的前端交互界面。
在KWDB中创建数据库和表存储饮料信息。可使用kwbase CLI工具连接KWDB,创建名为vending_machine的数据库:CREATE DATABASE vending_machine;。
接着在数据库内创建drinks表,存储饮料名称、价格、库存等信息:
CREATE TABLE vending_machine.drinks ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, price DECIMAL(10, 2) NOT NULL, stock INT NOT NULL );
插入一些初始饮料数据:
INSERT INTO vending_machine.drinks (name, price, stock) VALUES ('可乐', 3.00, 10), ('雪碧', 2.50, 10), ('橙汁', 4.00, 10);
借助Flask框架开发服务端接口,实现饮料查询、购物车结算等功能。创建app.py文件,编写如下代码:
from flask import Flask, jsonify, request, render_template import psycopg app = Flask(__name__) # 连接KWDB数据库 def connect_kwdb(): url = "postgresql://root@你的云服务器IP:26257/defaultdb" try: conn = psycopg.connect(url) return conn except psycopg.Error as e: print(f"连接KWDB失败: {e}") return None def query_data(): goods={} conn = connect_kwdb() if not conn: return jsonify({"error": "无法连接数据库"}), 500 cursor = conn.cursor() try: cursor.execute("SELECT name, price, stock FROM vending_machine.drinks;") result = cursor.fetchall() data=[] if len(result) > 0: columns = [desc[0] for desc in cursor.description] table_data = [{columns[i]: row[i] for i in range(len(columns))} for row in result] data.extend(table_data) # 提交事务并关闭连接 conn.commit() except psycopg.Error as e: return jsonify({"error": f"查询饮料失败: {e}"}), 500 finally: cursor.close() conn.close() for i in data: goods[i['name']]=i['price'] return goods # 将数据库取出来的数据赋值给goods goods=query_data() @app.route('/') def index(): return render_template('index.html',goods=goods) @app.route('/goods', methods=['GET']) def get_goods(): return jsonify(goods) # 购物车结算接口 @app.route('/checkout', methods=['POST']) def checkout(): cart = request.json.get('cart') if not cart: return jsonify({"error": "购物车数据为空"}), 400 conn = connect_kwdb() if not conn: return jsonify({"error": "无法连接数据库"}), 500 cursor = conn.cursor() total_price = 0 for drink, count in cart.items(): try: cursor.execute("SELECT price, stock FROM vending_machine.drinks WHERE name = %s", (drink,)) drink_info = cursor.fetchone() if drink_info: price, stock = drink_info if stock < count: return jsonify({"error": f"{drink}库存不足"}), 400 total_price += price * count except psycopg.Error as e: return jsonify({"error": f"结算失败: {e}"}), 500 try: for drink, count in cart.items(): cursor.execute("UPDATE vending_machine.drinks SET stock = stock - %s WHERE name = %s", (count, drink)) conn.commit() return jsonify({'message': '结算成功', 'total_price': total_price}) except psycopg.Error as e: conn.rollback() return jsonify({"error": f"更新库存失败: {e}"}), 500 finally: cursor.close() conn.close() if __name__ == '__main__': app.run()
使用HTML、CSS和JavaScript构建前端页面,展示饮料列表、购物车及结算结果。在项目目录下创建templates文件夹,放入index.html文件:
<!DOCTYPE html> <html> <head> <title>饮料自动售货机</title> <style> body { font-family: Arial, sans-serif; margin: 0; padding: 20px; background-color: #f2f2f2; } .container { max-width: 800px; margin: 0 auto; background-color: #fff; padding: 30px; border-radius: 5px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); } h2 { color: #333; margin-top: 0; } .button { background-color: #4CAF50; color: white; padding: 10px 20px; border: none; cursor: pointer; font-size: 16px; border-radius: 3px; } .button:hover { opacity: 0.8; } .goods-list,.cart,.checkout-result { margin-bottom: 20px; } .goods-list-item { display: flex; align-items: center; justify-content: space-between; padding: 10px; border-bottom: 1px solid #ccc; } .goods-list-item:last-child { border-bottom: none; } .cart-item { display: flex; align-items: center; justify-content: space-between; padding: 10px; border-bottom: 1px solid #ccc; } .cart-item:last-child { border-bottom: none; } .success-message { color: #28a745; padding: 10px; border: 1px solid #28a745; border-radius: 4px; margin: 10px 0; } .error-message { color: #dc3545; padding: 10px; border: 1px solid #dc3545; border-radius: 4px; margin: 10px 0; } </style> </head> <body> <div class="container"> <h2>饮料列表</h2> <div class="goods-list" id="goods-list"></div> <hr> <h2>购物车</h2> <div class="cart" id="cart"></div> <button class="button" onclick="checkout()">结算</button> <hr> <h2>结算结果</h2> <div class="checkout-result" id="checkout-result"></div> </div> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> const cart = {}; // 发起HTTP请求获取商品数据 axios.get("/goods") .then(response => { const goodsData = response.data; console.log('========',goodsData) // 渲染商品列表 const goodsListDiv = document.getElementById('goods-list'); for (const drink in goodsData) { const price = goodsData[drink]; const drinkDiv = document.createElement('div'); const drinkText = document.createTextNode(drink + ": " + price + " 元"); drinkDiv.appendChild(drinkText); const addButton = document.createElement('button'); addButton.textContent = "加入购物车"; addButton.addEventListener('click', function() { addToCart(drink); }); drinkDiv.appendChild(addButton); goodsListDiv.appendChild(drinkDiv); } }) .catch(error => { console.error(error); }); // 添加到购物车的逻辑 function addToCart(drink) { if (cart.hasOwnProperty(drink)) { cart[drink]++; } else { cart[drink] = 1; } renderCart(); } // 渲染购物车 function renderCart() { const cartDiv = document.getElementById('cart'); cartDiv.innerHTML = ''; for (const drink in cart) { const quantity = cart[drink]; const itemDiv = document.createElement('div'); const itemText = document.createTextNode(drink + ": " + quantity + "杯"); itemDiv.appendChild(itemText); cartDiv.appendChild(itemDiv); } } // 结算函数 function checkout() { axios.post('/checkout', {cart: cart}) .then(response => { const resultDiv = document.getElementById('checkout-result'); // 清空之前的样式和内容 resultDiv.innerHTML = ''; resultDiv.className = ''; // 处理成功响应 if (response.data.message === '结算成功') { const total_price = response.data.total_price; resultDiv.className = 'success-message'; resultDiv.innerHTML = ` ${response.data.message}<br>总消费金额:${total_price}元`; } // 处理其他可能的成功状态 else { resultDiv.className = 'error-message'; resultDiv.textContent = response.data.error || '未知响应'; } }) .catch(error => { const resultDiv = document.getElementById('checkout-result'); // 清空之前的样式和内容 resultDiv.innerHTML = ''; resultDiv.className = 'error-message'; if (error.response) { // 处理HTTP状态码为4xx/5xx的响应 const serverError = error.response.data.error; if (serverError) { resultDiv.innerHTML = ` 错误:${serverError}`; } else { resultDiv.textContent = `请求错误:${error.response.status}`; } } else if (error.request) { // 请求已发送但没有收到响应 resultDiv.textContent = "网络错误,请检查连接状态"; } else { // 其他错误 resultDiv.textContent = `请求失败:${error.message}`; } }); } </script> </body> </html>
在项目目录下,执行python app.py启动服务。若一切正常,可在浏览器中访问http://127.0.0.1:5000查看自动售卖机页面。用户能看到饮料列表及库存信息,点击“加入购物车”按钮添加饮料,结算时系统会检查库存并计算总价,同时更新数据库中的库存数据。
通过Python与KWDB的协同工作,成功打造了一个功能完备的自动售卖机系统。KWDB强大的数据存储和管理能力,确保饮料数据的高效处理;Python凭借丰富的库和简洁的语法,让开发过程变得轻松便捷。后续可进一步优化系统,如添加用户登录注册功能、完善库存预警机制等,不断提升用户体验。希望本文能为大家在相关开发领域提供有益参考,激发更多创新实践。