作者:大师兄6668
原文链接:https://blog.csdn.net/qq_41308872/article/details/147178215
在开发技术不断革新的当下,将Python的灵活编程能力与KWDB强大的数据管理性能相结合,能创造出功能丰富且高效的应用程序。本文将带领大家利用这两者打造一个自动售卖机系统,从环境搭建、功能实现到最终优化,逐步揭开项目的神秘面纱。
在前三篇博文中,我们已经成功在 Centos 云服务中通过 Docker 安装了 KWDB,
在 CentOS 云服务中通过 Docker 安装 KWDB数据库
并且掌握了在云服务器上直接连接 KWDB 进行增删改查的操作方法。
【云服务器连接已部署 KWDB 并进行增删改查操作】完整指南
而且深入探索如何通过 Python 语言连接 KWDB,
【通过 Python 连接 KWDB 数据库】的完整步骤与示例
接下来,我们利用这些知识,直接做一个简单的项目——《智能自动售卖机》
我们借助 Python 丰富的生态库,进一步来拓展 KWDB 在数据处理和应用开发方面的能力。
开发环境配置
安装Python
Python作为项目的核心开发语言,可从Python官方网站下载安装包进行安装。建议安装最新稳定版本,以获取更好的性能和功能支持。安装过程中,记得勾选“Add Python to PATH”选项,方便后续在命令行中直接调用Python。
安装KWDB
若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服务。
安装相关Python库
项目中需使用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凭借丰富的库和简洁的语法,让开发过程变得轻松便捷。后续可进一步优化系统,如添加用户登录注册功能、完善库存预警机制等,不断提升用户体验。希望本文能为大家在相关开发领域提供有益参考,激发更多创新实践。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70027415/viewspace-3089766/ ,如需转载,请注明出处,否则将追究法律责任。