Python-UV环境管理实战

Python使用Flask开发一个web应用实现数据的增改查,使用dict模拟数据库操作;个人实现代码仓库:https://gitee.com/enzoism/python_uv_hello-flask


1-UV从0开始构建环境

最好在Pycharm打开项目之前,先使用uv进行项目的环境指定->source .venv/bin/activate

# 1-查看并指定环境
uv python list
uv python pin 3.11.4

# 2-进行项目创建
uv init hello-flask
cd hello-flask

# 3-指定本地运行环境
uv venv
source .venv/bin/activate

# 4-本地环境安装依赖
uv pip install flask


2-Flask代码开发

下面给出一个最小可运行的示例,演示如何仅用 Python 内置 dict 作为“数据库”,通过 Flask 实现一套完整的「增-改-查(单条)-列表」接口,并附带一个极简的 HTML 页面,方便直接测试。复制即可运行,无需安装任何数据库。


  1. 安装依赖

# 建议使用虚拟环境
python -m venv venv
source venv/bin/activate          # Windows 用 venv\Scripts\activate
pip install Flask==2.3.3

  1. 项目结构(单文件即可)

demo/
 ├─ app.py        # 所有代码放这里
 └─ templates/
     └─ index.html

  1. 代码实现

app.py

from flask import Flask, request, jsonify, render_template, abort

app = Flask(__name__)

# ------------------------------
# 用 dict 模拟数据库
# key 为自增整数,value 为字典对象
# ------------------------------
db = {}
next_id = 1   # 自增主键

# ------------------------------
# 路由:首页
# ------------------------------
@app.route('/')
def index():
    return render_template('index.html')

# ------------------------------
# 接口:列表 + 条件查询
# ------------------------------
@app.route('/api/users', methods=['GET'])
def list_users():
    """
    支持按 name 模糊查询
    例:/api/users?name=Tom
    """
    name_filter = request.args.get('name', '').strip().lower()
    items = [
        {'id': uid, **info}
        for uid, info in db.items()
        if not name_filter or name_filter in info['name'].lower()
    ]
    return jsonify(items)

# ------------------------------
# 接口:单条查询
# ------------------------------
@app.route('/api/users/<int:uid>', methods=['GET'])
def get_user(uid):
    if uid not in db:
        abort(404, description=f"user {uid} not found")
    return jsonify({'id': uid, **db[uid]})

# ------------------------------
# 接口:新增
# ------------------------------
@app.route('/api/users', methods=['POST'])
def create_user():
    global next_id
    data = request.get_json(force=True)
    if not data or 'name' not in data:
        return jsonify({'error': "`name` field required"}), 400

    record = {
        'name': data['name'].strip(),
        'age':  int(data.get('age', 0)),
        'city': data.get('city', '')
    }
    db[next_id] = record
    uid = next_id
    next_id += 1
    return jsonify({'id': uid, **record}), 201

# ------------------------------
# 接口:修改(全量更新)
# ------------------------------
@app.route('/api/users/<int:uid>', methods=['PUT'])
def update_user(uid):
    if uid not in db:
        abort(404, description=f"user {uid} not found")
    data = request.get_json(force=True)
    if not data:
        return jsonify({'error': "empty payload"}), 400

    db[uid]['name'] = data.get('name', db[uid]['name']).strip()
    db[uid]['age']  = int(data.get('age', db[uid]['age']))
    db[uid]['city'] = data.get('city', db[uid]['city'])
    return jsonify({'id': uid, **db[uid]})

# ------------------------------
# 接口:删除(可选)
# ------------------------------
@app.route('/api/users/<int:uid>', methods=['DELETE'])
def delete_user(uid):
    if uid not in db:
        abort(404, description=f"user {uid} not found")
    del db[uid]
    return '', 204

# ------------------------------
# 错误处理
# ------------------------------
@app.errorhandler(404)
def not_found(err):
    return jsonify({'error': str(err.description)}), 404

# ------------------------------
# 启动
# ------------------------------
if __name__ == '__main__':
    app.run(debug=True)

templates/index.html

<!doctype html>
<html>
<head>
  <meta charset="utf-8"/>
  <title>Flask + Dict CRUD</title>
  <style>
    body{font-family:Arial,Helvetica,sans-serif;margin:40px}
    table{border-collapse:collapse;width:100%}
    th,td{border:1px solid #ccc;padding:6px 10px;text-align:left}
    input[type=text],input[type=number]{width:90%}
  </style>
</head>
<body>
  <h2>用户管理(Flask + dict 版)</h2>

  <h3>新增 / 修改</h3>
  <form id="userForm">
    <input type="hidden" id="userId"/><br>
    <label>姓名:<input type="text" id="name" required/></label><br>
    <label>年龄:<input type="number" id="age" min="0"/></label><br>
    <label>城市:<input type="text" id="city"/></label><br>
    <button type="submit">保存</button>
    <button type="button" onclick="resetForm()">重置</button><br>
  </form>

  <h3>用户列表</h3>
  <input type="text" id="q" placeholder="按姓名模糊查询"/>
  <button onclick="loadList()">搜索</button>
  <table>
    <thead><tr><th>ID</th><th>姓名</th><th>年龄</th><th>城市</th><th>操作</th></tr></thead>
    <tbody id="list"></tbody>
  </table>

<script>
const API = '/api/users';
function resetForm(){
  document.getElementById('userForm').reset();
  document.getElementById('userId').value='';
}
async function loadList(){
  const q=document.getElementById('q').value.trim();
  const res=await fetch(API+(q?`?name=${q}`:''));
  const data=await res.json();
  const html=data.map(u=>`
    <tr>
      <td>${u.id}</td><td>${u.name}</td><td>${u.age}</td><td>${u.city}</td>
      <td>
        <button onclick="editUser(${u.id},'${u.name}',${u.age},'${u.city}')">改</button>
        <button onclick="delUser(${u.id})">删</button>
      </tr>`).join('');
  document.getElementById('list').innerHTML=html;
}
function editUser(id,name,age,city){
  document.getElementById('userId').value=id;
  document.getElementById('name').value=name;
  document.getElementById('age').value=age;
  document.getElementById('city').value=city;
}
async function delUser(id){
  await fetch(`${API}/${id}`,{method:'DELETE'});
  loadList();
}
document.getElementById('userForm').addEventListener('submit',async e=>{
  e.preventDefault();
  const id=document.getElementById('userId').value;
  const payload={
    name:document.getElementById('name').value.trim(),
    age:Number(document.getElementById('age').value),
    city:document.getElementById('city').value.trim()
  };
  const url=id?`${API}/${id}`:API;
  const method=id?'PUT':'POST';
  await fetch(url,{method,headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)});
  resetForm();
  loadList();
});
// 初始化
loadList();
</script>
</body>
</html>

  1. 运行 & 验证

python app.py
# 默认 http://127.0.0.1:5000

打开浏览器即可进行「新增/查询/修改/删除」操作。所有数据仅保存在内存 dict 中,重启进程即清空。


Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐