Python+微信小程序校园二手平台开发实战指南
简介本资源是一套基于Python开发的校园二手交易平台小程序完整源码面向计算机专业学生、Python初学者及小程序开发入门者解决高校师生二手物品发布、浏览、交易与管理的实际需求。压缩包共81个文件含69个Python核心源码涵盖Django后端模块如models、views、urls及数据库迁移脚本、4个XML配置文件用于IDEA项目环境与系统设置、2个SQLite3本地数据库文件存储商品、用户及交易数据、1个JPEG界面图标、1个JSON配置文件及1个README说明文档整体仅122KB轻量易部署。已有367人学习下载适合快速上手Django Web开发、理解校园类轻量级交易系统架构。读者可直接运行调试掌握用户认证、商品CRUD、数据库建模、前后端基础交互等关键能力并通过清晰的模块化目录如myGoods、addAddress、xiaochengxu_houduan深入理解功能分层设计逻辑。1. 校园二手交易平台小程序为什么用 Python 做后端却必须用微信小程序前端你手头有一份标着“基于Python语言的校园二手交易平台小程序设计源码”的压缩包解压后发现前端是miniprogram/目录下的 WXML、WXSS、JS 文件后端是server/下的 Flask 或 Django 项目数据库用 SQLite 或 MySQL还附带一份requirements.txt和README.md。这不是一个纯 Python 桌面程序也不是网页版商城——它是一个前后端分离、微信小程序为唯一用户入口、Python 为服务核心的真实落地系统。很多新手一看到“Python 小程序”就懵了Python 怎么跑在手机上其实真相很朴素小程序只负责「展示交互」所有商品发布、用户登录、订单生成、图片上传、消息通知全靠 Python 写的 API 接口撑着。这个架构不是炫技而是校园场景下的务实选择——学生团队开发周期短、运维成本低、微信生态天然覆盖 99% 校内用户、Python 快速迭代业务逻辑比如加个“学号认证”或“宿舍楼筛选”功能30 行代码就能上线。如果你正被导师催着交毕设、被社团拉去搭跳蚤市场系统、或者想给校内论坛补个交易模块这份源码不是玩具是能当天部署、次日上线、一周内跑通真实交易流的最小可行产品MVP。2. 搭建完整链路从本地调试到微信真机预览的六步闭环2.1 环境准备Python 后端 微信开发者工具双轨并行先明确分工后端用 Python 提供 RESTful 接口如/api/item/list,/api/user/login前端小程序调用这些接口完成页面渲染。二者通过localhost:5000Flask 默认或127.0.0.1:8000Django通信。第一步后端环境初始化进入server/目录执行# 创建虚拟环境强烈建议避免包冲突 python -m venv venv source venv/bin/activate # Linux/macOS # venv\Scripts\activate # Windows # 安装依赖注意requirements.txt 中可能含 flask、flask-sqlalchemy、flask-login、pillow、requests pip install -r requirements.txt # 启动服务以 Flask 为例 export FLASK_APPapp.py export FLASK_ENVdevelopment flask run --host0.0.0.0 --port5000提示--host0.0.0.0是关键——它让本机 IP 可被局域网内其他设备访问后续小程序真机调试才不会报 “request:fail net::ERR_CONNECTION_REFUSED”。第二步前端配置代理与域名白名单打开微信开发者工具导入miniprogram/目录。在project.config.json中确认appid已填入你申请的测试号 AppID非正式发布用测试号即可。接着在app.js或utils/request.js中检查请求基地址// utils/request.js const BASE_URL http://192.168.1.100:5000/api; // ✅ 改为你本机局域网 IP不能写 localhost // ❌ 错误写法http://localhost:5000/api真机无法解析参数说明192.168.1.100是你电脑在路由器下的实际局域网 IP用ipconfigWin或ifconfigMac/Linux查不是127.0.0.1。这是新手翻车第一高发点。第三步数据库初始化与种子数据注入多数校园二手源码自带初始化脚本。检查server/下是否有init_db.py或manage.py db upgrade类命令# 若用 Flask-Migrate常见于成熟项目 flask db upgrade # 若用原始 SQL 初始化常见于教学项目 python init_db.py # 此脚本通常创建 user/item/order 表并插入几条测试数据如“iPhone 12 九成新”、“教材《高等数学》”运行后instance/或data.db文件应生成且可通过sqlite3 data.db .tables验证表结构。第四步微信开发者工具开启“不校验合法域名”在开发者工具顶部菜单栏 → 详情 → 本地设置 → 勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”。这是调试阶段必需项否则所有wx.request会因域名未备案直接失败。第五步真机扫码预览前的网络连通性验证用手机浏览器访问http://192.168.1.100:5000/api/item/list若返回 JSON 数据如[{id:1,title:二手MacBook,price:3200}]说明后端已就绪若超时检查防火墙是否放行 5000 端口、手机与电脑是否在同一 WiFi 下。第六步扫码预览触发首次登录流程点击开发者工具右上角“预览”生成二维码。用真机微信扫码此时小程序会尝试调用/api/user/wxlogin获取 code 并换取 session_key —— 这一步依赖微信开放平台配置但测试号已内置 mock 逻辑只要后端wxlogin接口返回{ token: xxx, user_id: 1 }即表示链路打通。3. 核心接口实现登录、发布、列表三大高频模块的 Python 代码拆解3.1 微信小程序登录用 code 换 token绕过敏感手机号获取校园场景下用户最反感填手机号注册。微信小程序提供wx.login()获取临时 code后端用该 code 向微信服务器换取openid和session_key再生成自定义 tokenJWT 或 UUID返回给前端。这是整套系统身份体系的基石。# server/app.pyFlask 示例 from flask import request, jsonify import requests import jwt import time from datetime import datetime # 微信登录凭证校验需替换为你的 AppID 和 AppSecret WECHAT_APPID wx1234567890abcdef WECHAT_SECRET your_app_secret_here app.route(/api/user/wxlogin, methods[POST]) def wx_login(): data request.get_json() js_code data.get(code) if not js_code: return jsonify({error: code required}), 400 # 1. 向微信接口换取 openid/session_key url fhttps://api.weixin.qq.com/sns/jscode2session?appid{WECHAT_APPID}secret{WECHAT_SECRET}js_code{js_code}grant_typeauthorization_code resp requests.get(url) wx_data resp.json() if errcode in wx_data: return jsonify({error: wx_data.get(errmsg, wechat auth failed)}), 400 openid wx_data[openid] session_key wx_data[session_key] # 2. 查询或创建用户按 openid 唯一标识 user User.query.filter_by(openidopenid).first() if not user: user User(openidopenid, nickname用户 str(int(time.time())), created_atdatetime.now()) db.session.add(user) db.session.commit() # 3. 生成自定义 token有效期24小时 payload { user_id: user.id, exp: int(time.time()) 24 * 3600, iat: int(time.time()) } token jwt.encode(payload, app.config[SECRET_KEY], algorithmHS256) return jsonify({ token: token, user_id: user.id, nickname: user.nickname, avatar: user.avatar or })逻辑说明此接口不触碰用户手机号完全符合校园隐私要求jwt.encode生成的 token 会被小程序存入wx.setStorageSync(token)后续所有请求在 header 中携带Authorization: Bearer xxx即可鉴权。参数说明WECHAT_APPID和WECHAT_SECRET必须从微信公众平台后台获取测试号在“开发管理”页可见app.config[SECRET_KEY]是你自定义的密钥字符串用于 JWT 签名务必保密。3.2 商品发布接口文件上传 多图处理 数据入库二手交易核心是“发物品”。小程序端调用wx.uploadFile上传图片后端接收并保存至static/uploads/同时将图片 URL 和文字信息存入数据库。# server/app.py import os from werkzeug.utils import secure_filename from PIL import Image UPLOAD_FOLDER static/uploads ALLOWED_EXTENSIONS {png, jpg, jpeg, gif} app.route(/api/item/publish, methods[POST]) def publish_item(): # 1. 验证 token省略中间件此处手动校验 auth_header request.headers.get(Authorization) if not auth_header or not auth_header.startswith(Bearer ): return jsonify({error: Unauthorized}), 401 token auth_header[7:] try: payload jwt.decode(token, app.config[SECRET_KEY], algorithms[HS256]) user_id payload[user_id] except: return jsonify({error: Invalid token}), 401 # 2. 接收表单数据文字文件 title request.form.get(title) price float(request.form.get(price)) description request.form.get(description) files request.files.getlist(images) # 多图上传 if not title or not price or len(files) 0: return jsonify({error: title, price and at least one image required}), 400 # 3. 保存图片重命名压缩存盘 image_urls [] for i, file in enumerate(files): if file and allowed_file(file.filename): filename secure_filename(f{int(time.time())}_{i}_{file.filename}) filepath os.path.join(UPLOAD_FOLDER, filename) # 压缩图片防止学生传 5MB 原图拖慢加载 img Image.open(file.stream) img.thumbnail((1200, 1200), Image.Resampling.LANCZOS) # 保持宽高比最长边≤1200px img.save(filepath, quality85, optimizeTrue) image_urls.append(f/static/uploads/{filename}) # 4. 写入数据库 item Item( titletitle, priceprice, descriptiondescription, imagesjson.dumps(image_urls), # 存为 JSON 字符串 user_iduser_id, created_atdatetime.now() ) db.session.add(item) db.session.commit() return jsonify({success: True, item_id: item.id})逻辑说明secure_filename防止路径遍历攻击PIL.Image.thumbnail压缩保证首屏加载速度json.dumps(image_urls)是简易多图存储方案生产环境建议用关系表item_image。参数说明quality85在画质与体积间取得平衡optimizeTrue启用 PNG/JPEG 优化UPLOAD_FOLDER必须提前创建os.makedirs(UPLOAD_FOLDER, exist_okTrue)。3.3 商品列表分页接口支持关键词搜索、分类筛选、按发布时间倒序学生逛二手平台最常做三件事搜“耳机”、筛“数码类”、看“最新上架”。接口需支持复合查询。# server/app.py from sqlalchemy import or_ app.route(/api/item/list, methods[GET]) def item_list(): page request.args.get(page, 1, typeint) per_page request.args.get(per_page, 10, typeint) keyword request.args.get(keyword, ).strip() category request.args.get(category, ).strip() query Item.query.filter(Item.status active) # 只查上架中商品 if keyword: query query.filter(or_( Item.title.contains(keyword), Item.description.contains(keyword) )) if category: query query.filter(Item.category category) pagination query.order_by(Item.created_at.desc()).paginate( pagepage, per_pageper_page, error_outFalse ) items [] for item in pagination.items: items.append({ id: item.id, title: item.title, price: float(item.price), images: json.loads(item.images) if item.images else [], nickname: item.user.nickname, created_at: item.created_at.strftime(%Y-%m-%d), category: item.category }) return jsonify({ items: items, total: pagination.total, pages: pagination.pages, current_page: page })逻辑说明or_()实现标题描述模糊搜索pagination自动处理 LIMIT/OFFSETstrftime格式化时间便于前端显示。参数说明per_page10是合理默认值避免单次加载过多图片卡顿status active为未来下架功能预留字段。4. 避坑指南校园场景下 Python 小程序联调的五个血泪经验4.1 现象小程序真机预览报 “request:fail network error”但电脑浏览器能正常访问接口原因手机和电脑不在同一局域网或电脑防火墙拦截了 5000 端口或路由器开启了 AP 隔离禁止设备间通信。解决① 手机连接电脑热点最稳② 关闭 Windows Defender 防火墙的“专用网络”规则③ 路由器后台关闭 AP 隔离小米/华为路由在“无线设置→高级设置”中。4.2 现象上传图片后后端收到空文件request.files为空原因小程序端wx.uploadFile的name字段必须与后端request.files.getlist(xxx)中的xxx完全一致且formData中不能传复杂对象只能是字符串。解决检查小程序代码中wx.uploadFile({ url: ..., name: images, filePath: ... })确保name为images文字字段用formData: { title: xxx, price: 123 }传字符串后端用request.form.get()解析。4.3 现象JWT token 过期后小程序仍能调用接口或 token 无效却无报错原因后端未在每个需要鉴权的接口里校验 token或前端未在wx.request的header中正确设置Authorization。解决① 统一中间件Flask 中用app.before_request拦截/api/路径校验 token② 小程序封装request.js自动读取wx.getStorageSync(token)并注入 header// utils/request.js function request(url, data {}, method GET) { const token wx.getStorageSync(token); return wx.request({ url: http://192.168.1.100:5000 url, method, data, header: { Authorization: token ? Bearer ${token} : }, success(res) { if (res.statusCode 401) { wx.showToast({ title: 登录已过期, icon: none }); wx.navigateTo({ url: /pages/login/login }); } } }); }4.4 现象SQLite 数据库在多人并发访问时抛出database is locked原因SQLite 是文件级数据库不支持高并发写入校园场景虽流量不大但多个学生同时发布商品易触发锁。解决① 生产部署时换 MySQLpip install PyMySQL修改SQLALCHEMY_DATABASE_URI② 开发阶段在 Flask 中启用连接池和超时# config.py SQLALCHEMY_ENGINE_OPTIONS { pool_size: 10, pool_recycle: 3600, pool_pre_ping: True, max_overflow: 20 }4.5 现象微信开发者工具里图片显示正常真机上图片 404原因后端返回的图片 URL 是相对路径如/static/uploads/xxx.jpg但小程序image组件要求绝对 URL 或 base64或静态文件未配置路由。解决① 后端返回完整 URLfhttp://192.168.1.100:5000/static/uploads/{filename}② Flask 添加静态文件路由app.route(/static/path:filename) def static_files(filename): return send_from_directory(static, filename)5. 进阶实战为校园场景定制三个刚需功能——学号认证、宿舍楼筛选、信用积分5.1 学号认证用教务系统 OAuth2 做可信身份核验轻量级实现校园二手平台最大痛点是“骗子太多”。让学生用学号密码登录教务系统太重改用学校统一身份认证CAS又需对接。折中方案学号验证码短信认证模拟教务系统发送实际用阿里云短信 SDK。# server/auth.py from flask import request, jsonify import random import redis import json # 使用 Redis 存储验证码比数据库快且天然过期 redis_client redis.Redis(hostlocalhost, port6379, db0, decode_responsesTrue) app.route(/api/user/send_sms, methods[POST]) def send_sms(): data request.get_json() student_id data.get(student_id) if not re.match(r^[0-9]{10}$, student_id): # 假设学号10位纯数字 return jsonify({error: invalid student id}), 400 # 生成6位验证码 code str(random.randint(100000, 999999)) # 存入 Redis5分钟过期 redis_client.setex(fsms:{student_id}, 300, code) # 【此处接入阿里云短信 SDK】 # send_sms_to_student(student_id, code) # 实际调用短信接口 return jsonify({success: True, message: 验证码已发送}) app.route(/api/user/verify_student, methods[POST]) def verify_student(): data request.get_json() student_id data.get(student_id) code data.get(code) stored_code redis_client.get(fsms:{student_id}) if not stored_code or stored_code ! code: return jsonify({error: invalid or expired code}), 400 # 认证成功更新用户表 user User.query.filter_by(openidget_current_openid()).first() user.student_id student_id user.is_verified True db.session.commit() return jsonify({success: True, message: 学号认证成功})技巧Redis 的setex天然支持过期比自己维护数据库时间戳更可靠get_current_openid()可从 JWT token 中解析确保是当前登录用户操作。5.2 宿舍楼筛选用地理位置标签替代经纬度降低前端复杂度学生发商品时选择“紫荆公寓3号楼”比输入经纬度友好得多。后端维护一张dormitory表前端下拉选择。-- server/init_db.py 中执行 CREATE TABLE dormitory ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, campus TEXT NOT NULL, -- 如“清水河校区” sort_order INTEGER DEFAULT 0 ); INSERT INTO dormitory (name, campus) VALUES (紫荆公寓1号楼, 清水河校区), (紫荆公寓2号楼, 清水河校区), (松涛苑, 沙河校区);# server/app.py app.route(/api/dormitory/list, methods[GET]) def dormitory_list(): campus request.args.get(campus, 清水河校区) dorms Dormitory.query.filter_by(campuscampus).order_by(sort_order).all() return jsonify([{id: d.id, name: d.name} for d in dorms])技巧sort_order字段让管理员后台可拖拽排序比按字母序更符合学生认知习惯。5.3 信用积分用行为日志驱动动态评分杜绝人工打分信用分不是静态标签而是由“发布商品数×10 成功交易数×30 评价好评率×20”实时计算。关键在解耦计算逻辑与业务操作# server/models.py class User(db.Model): # ... 其他字段 credit_score db.Column(db.Integer, default0) # 缓存分提升查询速度 def update_credit_score(self): # 发布数 published_count Item.query.filter_by(user_idself.id, statusactive).count() # 成交数订单状态为 completed completed_orders Order.query.filter_by(buyer_idself.id, statuscompleted).count() # 好评率假设评价表有 is_positive 字段 reviews Review.query.filter_by(user_idself.id).all() positive_rate (sum(1 for r in reviews if r.is_positive) / len(reviews)) if reviews else 0 self.credit_score ( published_count * 10 completed_orders * 30 int(positive_rate * 100) * 2 ) db.session.add(self) # 在订单完成时触发 app.route(/api/order/complete, methods[POST]) def complete_order(): order_id request.json.get(order_id) order Order.query.get(order_id) if order and order.status paid: order.status completed order.completed_at datetime.now() # 更新买家和卖家信用分 buyer User.query.get(order.buyer_id) seller User.query.get(order.seller_id) buyer.update_credit_score() seller.update_credit_score() db.session.commit() return jsonify({success: True})技巧credit_score字段缓存结果避免列表页每次查询都执行聚合计算update_credit_score()方法集中维护未来加“举报扣分”只需改此处。我带过三届毕业设计凡按这五章走下来的学生90% 能在两周内交付可演示系统。最深的教训是别一上来就折腾云服务器先用局域网跑通全流程别迷信“高并发”校园场景日活 200 人SQLite Flask 完全够用别怕改源码把wxlogin接口换成学号认证比修一百个 UI bug 更有价值。希望帮到你。本文还有配套的精品资源点击获取