基于Django与微信小程序的全栈健康管理系统开发实战
如果你正在为计算机专业的毕业设计或课程设计寻找一个既有实际应用价值,又能充分展示你全栈开发能力的项目,那么“本地健康宝”系统绝对是一个值得深入研究的选题。它听起来像是一个简化版的健康码应用,但背后涉及的技术栈——Django后端、微信小程序前端、数据库设计、API接口开发——正是当前企业招聘时最看重的技能组合。
然而,很多同学在着手这类项目时,往往会陷入两个误区:要么只关注前端页面的炫酷效果,导致后端逻辑脆弱不堪;要么埋头写出一堆复杂的Django模型和视图,却不知道如何与微信小程序进行安全、高效的数据通信。最终,项目要么跑不起来,要么漏洞百出,离一个“可运行、可演示、可讲解”的合格毕业设计相去甚远。
本文将为你彻底拆解一个“基于Django的本地健康宝微信小程序系统”从零到一的实现过程。我们不止提供源码和文档,更重要的是,我会带你理解每个技术决策背后的原因,避开开发中最容易踩的坑(比如微信登录集成、数据安全、前后端跨域),并手把手教你如何将Django后端与微信小程序前端无缝对接。无论你是想快速复现一个高分项目,还是希望真正掌握全栈开发的核心流程,这篇文章都能给你一条清晰的路径。
1. 项目核心要解决什么问题?不只是“扫码亮码”
在开始敲代码之前,我们必须明确这个项目的核心价值。它不是一个简单的信息展示系统,而是一个模拟真实场景的、轻量级的“健康状态管理与核验”平台。其主要解决以下几个关键问题:
- 用户端便捷性:用户通过微信小程序,可以免安装、快速完成个人健康信息的申报、查看,以及生成一个供核验的“健康码”(或状态标识)。
- 核验端高效性:管理员或核验人员(如门岗)可以通过小程序扫描用户的健康码,快速获取其健康状态,完成通行核验。
- 数据管理与安全性:所有用户健康数据需要在服务器端进行安全、有序的存储和管理,并确保数据传输过程的安全(即使作为本地项目,也应具备安全意识)。
- 全栈技术实践:为开发者(学生)提供一个完整的全栈开发闭环实践,涵盖数据库设计(MySQL/PostgreSQL/SQLite)、后端API开发(Django REST framework)、前端交互(微信小程序)和部署测试。
关键判断:这个项目的难点和亮点不在于“健康码”的UI设计,而在于前后端分离架构下的数据流设计、用户身份认证体系以及模拟真实业务逻辑的API接口规划。很多毕业设计在这里做得非常粗糙。
2. 技术栈选型与核心概念解析
为什么选择 Django + 微信小程序?这不是随意组合,而是基于技术生态和项目需求的理性选择。
| 技术组件 | 选型理由 | 在本项目中的核心作用 |
|---|---|---|
| Django (Python) | 生态成熟,“开箱即用”。自带Admin后台、ORM、用户认证等模块,能极大加速后端开发。Python语法简洁,适合快速原型开发。 | 构建RESTful API服务器,处理业务逻辑,操作数据库,提供管理员后台。 |
| Django REST Framework (DRF) | Django生态中构建API的事实标准。提供了序列化、视图集、认证、权限等强大工具,让API开发变得规范且高效。 | 快速构建供微信小程序调用的JSON格式API接口。 |
| 微信小程序 | 拥有巨大的用户基数,无需下载安装,体验接近原生App。提供丰富的原生组件和API(如扫码、地理位置)。 | 为用户和管理员提供交互界面,是收集数据和展示信息的终端。 |
| SQLite (开发)/MySQL (生产) | Django默认支持SQLite,无需额外安装,适合开发和演示。MySQL更适合正式部署,性能更优。 | 存储用户信息、健康申报记录、健康码状态等核心数据。 |
几个必须厘清的核心概念:
- “本地”的含义:这里的“本地”通常指项目部署在你自己的电脑或学校服务器上,用于课程演示或毕业答辩,而非真正上线服务公众。它强调的是开发环境和数据存储的本地化。
- 健康宝的核心数据流:
- 用户申报:用户填写体温、症状、旅居史等信息,提交至Django后端。
- 状态计算:后端根据预设规则(如体温>37.3℃则状态异常)自动计算用户的健康状态(如“绿码”、“黄码”、“红码”)。
- 生成与展示:后端生成一个代表该状态的唯一标识(如一个加密的字符串或二维码内容),返回给小程序前端展示。
- 核验流程:核验员扫码,小程序将码内容发送至后端,后端解码并返回该用户的实时健康状态,供核验员判断。
- 前后端通信:微信小程序通过
wx.request调用Django DRF提供的API接口。这里最大的挑战是解决跨域问题(CORS)和设计安全的认证机制(如使用JWT或微信小程序自带的登录凭证)。
3. 开发环境准备与项目初始化
在开始任何编码工作前,一个稳定、一致的开发环境是成功的基石。
3.1 基础环境配置
- Python环境:推荐使用 Python 3.8 或 3.9。避免使用过新或过旧的版本,以保证第三方库的兼容性。
# 检查Python版本 python --version # 或 python3 --version - 包管理工具:使用
pip进行Python包管理。建议使用虚拟环境(venv)隔离项目依赖。# 创建虚拟环境 python -m venv venv # 激活虚拟环境 (Windows) venv\Scripts\activate # 激活虚拟环境 (macOS/Linux) source venv/bin/activate - 代码编辑器:VSCode 或 PyCharm 都是绝佳选择,它们对Django和微信小程序开发都有很好的支持。
3.2 初始化Django项目与核心依赖安装
在虚拟环境激活的状态下,执行以下命令:
# 安装Django和Django REST framework pip install django djangorestframework # 可选但推荐:用于处理跨域请求 pip install django-cors-headers # 创建Django项目,项目名称为 `health_code_backend` django-admin startproject health_code_backend . # 创建一个名为 `api` 的Django应用,用于存放所有API相关代码 python manage.py startapp api安装完成后,你的项目目录结构应大致如下:
health_code_backend/ │ manage.py │ ├── api/ # 新创建的API应用 │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── models.py # 数据模型定义 │ ├── tests.py │ ├── views.py # 视图逻辑 │ └── ... │ └── health_code_backend/ # 项目配置目录 ├── __init__.py ├── settings.py # 项目配置文件,需要重点修改 ├── urls.py # 项目URL路由 ├── asgi.py └── wsgi.py3.3 微信小程序环境准备
- 前往 微信公众平台 注册并登录,选择“小程序”类型。
- 在开发管理页面,获取你的小程序的AppID,这在后续与后端通信时非常重要。
- 下载并安装 微信开发者工具 。
4. Django后端核心设计与实现
后端是整个系统的大脑,负责数据、逻辑和安全。我们按模块拆解。
4.1 数据模型设计 (Models)
在api/models.py中,我们需要定义核心的数据表。一个精简但完整的设计至少包含用户和健康记录。
# api/models.py from django.db import models from django.contrib.auth.models import AbstractUser # 扩展Django自带的用户模型,方便后续增加字段(如手机号) class User(AbstractUser): # 使用微信小程序的openid作为唯一标识,避免重复注册 openid = models.CharField(max_length=100, unique=True, blank=True, null=True) phone = models.CharField(max_length=15, blank=True, null=True) # 可以添加头像、昵称等字段,从小程序获取 avatar_url = models.URLField(blank=True, null=True) nick_name = models.CharField(max_length=100, blank=True, null=True) class Meta: db_table = 'user' # 健康申报记录 class HealthReport(models.Model): STATUS_CHOICES = ( ('green', '绿码'), ('yellow', '黄码'), ('red', '红码'), ) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='reports') # 申报信息 temperature = models.DecimalField(max_digits=3, decimal_places=1) # 体温 has_symptom = models.BooleanField(default=False) # 是否有症状 recent_travel = models.BooleanField(default=False) # 近期是否旅居高风险地区 report_time = models.DateTimeField(auto_now_add=True) # 申报时间 # 系统计算出的状态 health_status = models.CharField(max_length=10, choices=STATUS_CHOICES) # 健康码唯一标识(可以用UUID生成) code = models.CharField(max_length=50, unique=True) class Meta: db_table = 'health_report' ordering = ['-report_time'] # 按申报时间倒序排列 def __str__(self): return f'{self.user.username} - {self.health_status} at {self.report_time}'设计要点:
- 使用
AbstractUser继承,便于利用Django强大的认证系统。 openid是关键字段,用于关联微信用户。HealthReport表记录每次申报,health_status字段应根据业务规则自动计算(可在save方法或视图中实现)。code字段是生成“健康码”的基础,可以是UUID或包含用户和状态信息的加密字符串。
4.2 序列化器 (Serializers)
DRF的序列化器负责将模型实例转换为JSON数据(序列化),以及将JSON数据转换为模型实例(反序列化)。
# api/serializers.py from rest_framework import serializers from .models import User, HealthReport class UserSerializer(serializers.ModelSerializer): class Meta: model = User # 注意:密码等敏感字段不应包含在内 fields = ['id', 'username', 'openid', 'phone', 'avatar_url', 'nick_name'] class HealthReportSerializer(serializers.ModelSerializer): # 嵌套显示用户的部分信息 user_info = UserSerializer(source='user', read_only=True) class Meta: model = HealthReport fields = ['id', 'user', 'user_info', 'temperature', 'has_symptom', 'recent_travel', 'report_time', 'health_status', 'code'] read_only_fields = ['report_time', 'health_status', 'code'] # 这些字段由系统自动生成4.3 视图与API端点 (Views & URLs)
这是业务逻辑的核心。我们创建几个关键的API。
# api/views.py from rest_framework import viewsets, permissions, status from rest_framework.decorators import action from rest_framework.response import Response from django.shortcuts import get_object_or_404 import uuid from .models import User, HealthReport from .serializers import UserSerializer, HealthReportSerializer class HealthReportViewSet(viewsets.ModelViewSet): """ 健康申报记录的增删改查视图集。 用户只能操作自己的记录。 """ serializer_class = HealthReportSerializer permission_classes = [permissions.IsAuthenticated] # 必须登录 def get_queryset(self): # 只返回当前用户的申报记录 return HealthReport.objects.filter(user=self.request.user) def perform_create(self, serializer): # 在创建记录时,自动关联当前用户,并生成健康码状态和code user = self.request.user data = serializer.validated_data # 简单的状态计算逻辑(示例,可根据实际情况复杂化) status = 'green' if data['temperature'] > 37.3 or data['has_symptom']: status = 'red' elif data['recent_travel']: status = 'yellow' # 生成一个唯一的code,例如:用户ID+时间戳+随机数的组合 # 这里使用UUID简化示例 health_code = f"{user.id}-{uuid.uuid4().hex[:8]}" # 保存实例 serializer.save(user=user, health_status=status, code=health_code) @action(detail=False, methods=['get']) def latest(self, request): """获取当前用户最新的健康申报记录(即最新的健康码)""" latest_report = self.get_queryset().first() # 因为已按时间倒序 if latest_report: serializer = self.get_serializer(latest_report) return Response(serializer.data) return Response({'detail': '暂无申报记录'}, status=status.HTTP_404_NOT_FOUND) @action(detail=True, methods=['get']) def verify(self, request, pk=None): """核验接口:通过健康码的code来查询健康状态(无需登录)""" # 这里假设通过报告ID(pk)来查,实际核验应该通过`code`字段查询 # 更合理的做法是单独一个不依赖pk的verify接口,接收code参数 report = self.get_object() # 这里仅作示例,实际应修改 # 返回核验所需的基本信息 return Response({ 'user': report.user.nick_name or report.user.username, 'health_status': report.get_health_status_display(), 'report_time': report.report_time })然后,在api/urls.py和项目主urls.py中配置路由。
# api/urls.py from django.urls import path, include from rest_framework.routers import DefaultRouter from . import views router = DefaultRouter() router.register(r'reports', views.HealthReportViewSet, basename='report') urlpatterns = [ path('', include(router.urls)), ]# health_code_backend/urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('api/', include('api.urls')), # 将所有API路由挂载到 /api/ 下 ]4.4 项目关键配置 (Settings)
修改health_code_backend/settings.py,这是项目的控制中心。
# health_code_backend/settings.py import os from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent SECRET_KEY = 'your-secret-key-here' # 生产环境务必更换! DEBUG = True # 开发时设为True,部署时务必设为False ALLOWED_HOSTS = ['*'] if DEBUG else ['your-server-ip', 'localhost'] # 按需修改 # 关键:添加应用和第三方应用 INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # 第三方 'rest_framework', 'corsheaders', # 处理跨域 # 本地应用 'api.apps.ApiConfig', ] # 使用自定义用户模型 AUTH_USER_MODEL = 'api.User' # 中间件:CORS中间件要放得尽量靠前 MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', # 新增 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] # 配置CORS,允许微信小程序开发者工具本地请求(极度重要!) CORS_ALLOW_ALL_ORIGINS = DEBUG # 开发时允许所有源,生产环境必须指定 # 或者更精确地配置: # CORS_ALLOWED_ORIGINS = [ # "https://your-domain.com", # "http://localhost:8080", # 微信开发者工具调试器地址 # ] # 数据库配置(使用SQLite,简单) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } # 静态文件配置 (CSS, JavaScript, Images) STATIC_URL = 'static/' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') # 收集静态文件目录 # DRF全局配置 REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.SessionAuthentication', # 用于Admin 'rest_framework.authentication.BasicAuthentication', ], 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', # 默认需要登录 ], 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 10 }4.5 用户认证与微信登录集成
这是连接微信小程序和后端的桥梁。微信小程序登录流程如下:
- 小程序端调用
wx.login()获取临时code。 - 小程序端将
code发送给你的Django后端。 - Django后端用
code、小程序的AppID和AppSecret请求微信接口服务,换取openid和session_key。 - Django后端根据
openid查找或创建用户,并生成一个自定义的登录态(如Token)返回给小程序。
由于涉及微信服务器通信,我们需要一个视图来处理这个逻辑。
# api/views.py (续) import requests from django.conf import settings from rest_framework.decorators import api_view, permission_classes from rest_framework.permissions import AllowAny @api_view(['POST']) @permission_classes([AllowAny]) # 登录接口无需认证 def wechat_login(request): """ 微信小程序登录接口。 接收前端传来的code,向微信服务器换取openid,并注册/登录本地用户。 """ code = request.data.get('code') if not code: return Response({'error': 'Code is required'}, status=status.HTTP_400_BAD_REQUEST) # 你的小程序AppID和AppSecret(应从环境变量读取,切勿硬编码!) APP_ID = 'your-app-id' APP_SECRET = 'your-app-secret' # 向微信服务器请求 wechat_url = f'https://api.weixin.qq.com/sns/jscode2session?appid={APP_ID}&secret={APP_SECRET}&js_code={code}&grant_type=authorization_code' response = requests.get(wechat_url) data = response.json() openid = data.get('openid') session_key = data.get('session_key') # 注意:session_key不应传给前端 if not openid: return Response({'error': 'Failed to get openid from WeChat'}, status=status.HTTP_400_BAD_REQUEST) # 根据openid查找或创建用户 user, created = User.objects.get_or_create(openid=openid) if created: # 新用户,可以设置默认用户名等 user.username = f'wx_user_{openid[-8:]}' user.set_unusable_password() # 微信登录用户不需要Django密码 user.save() # 这里应该生成一个Token(例如使用DRF的Token或JWT)返回给前端 # 为简化,我们使用Django的login机制(基于Session),但小程序通常用Token # 示例:使用DRF内置的TokenAuthentication(需安装`rest_framework.authtoken`) from rest_framework.authtoken.models import Token token, _ = Token.objects.get_or_create(user=user) # 返回用户基本信息和token serializer = UserSerializer(user) return Response({ 'user': serializer.data, 'token': token.key # 前端后续请求需在Header中携带:Authorization: Token <token_key> })别忘了在api/urls.py中添加这个登录路由:
# api/urls.py from .views import wechat_login urlpatterns = [ path('', include(router.urls)), path('wechat-login/', wechat_login, name='wechat-login'), # 新增 ]5. 微信小程序前端核心功能实现
前端负责交互和展示。我们使用微信小程序原生开发框架。
5.1 项目结构与配置
在微信开发者工具中创建小程序项目,填写你的AppID。项目基本结构如下:
miniprogram/ ├── pages/ │ ├── index/ # 首页,展示健康码 │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss │ ├── report/ # 健康申报页 │ └── verify/ # 扫码核验页 ├── utils/ │ └── request.js # 封装的网络请求模块 ├── app.js # 小程序入口文件 ├── app.json # 全局配置 ├── app.wxss # 全局样式 └── project.config.json # 项目配置5.2 封装网络请求
在utils/request.js中封装一个通用的请求函数,便于管理Token和基础URL。
// utils/request.js const BASE_URL = 'http://127.0.0.1:8000/api'; // 你的Django后端地址,本地开发用localhost或IP const request = (url, method, data) => { return new Promise((resolve, reject) => { wx.request({ url: BASE_URL + url, method: method, data: data, header: { 'Content-Type': 'application/json', 'Authorization': `Token ${wx.getStorageSync('token')}` // 从本地存储读取token }, success(res) { if (res.statusCode >= 200 && res.statusCode < 300) { resolve(res.data); } else { reject(res.data); } }, fail(err) { reject(err); } }); }); }; // 导出常用的方法 export const get = (url, data) => request(url, 'GET', data); export const post = (url, data) => request(url, 'POST', data); export const put = (url, data) => request(url, 'PUT', data); export const del = (url, data) => request(url, 'DELETE', data); export default request;5.3 用户登录与状态管理
在app.js的onLaunch生命周期中,执行登录逻辑,获取Token并存储。
// app.js import { post } from './utils/request'; App({ onLaunch() { // 微信登录 wx.login({ success: async (res) => { if (res.code) { try { // 调用后端登录接口 const loginRes = await post('/wechat-login/', { code: res.code }); // 存储token和用户信息 wx.setStorageSync('token', loginRes.token); wx.setStorageSync('userInfo', loginRes.user); console.log('登录成功', loginRes.user); } catch (error) { console.error('登录失败', error); wx.showToast({ title: '登录失败', icon: 'none' }); } } else { console.error('获取登录code失败', res.errMsg); } } }); }, globalData: { userInfo: null } });5.4 首页:展示健康码
首页 (pages/index/index) 主要展示用户最新的健康状态和健康码。
<!-- pages/index/index.wxml --> <view class="container"> <view class="user-info" wx:if="{{userInfo}}"> <image class="avatar" src="{{userInfo.avatar_url || '/images/avatar.png'}}"></image> <text class="nickname">{{userInfo.nick_name || '微信用户'}}</text> </view> <view class="health-card {{healthStatus}}"> <view class="status-text">健康状态:{{healthStatusText}}</view> <view class="code-section"> <!-- 这里可以生成二维码,使用第三方组件或服务 --> <text class="code" wx:if="{{healthCode}}">{{healthCode}}</text> <text class="hint">(模拟健康码)</text> </view> <view class="time">更新时间:{{reportTime}}</view> </view> <view class="actions"> <button type="primary" bindtap="navigateToReport">立即申报</button> <button bindtap="refreshCode">刷新状态</button> </view> <view class="history" wx:if="{{historyList.length > 0}}"> <view class="title">申报历史</view> <view class="history-item" wx:for="{{historyList}}" wx:key="id"> <text>{{item.report_time}} - {{item.health_status}}</text> <text>体温:{{item.temperature}}°C</text> </view> </view> </view>// pages/index/index.js import { get } from '../../utils/request'; Page({ data: { userInfo: null, healthStatus: 'gray', // gray, green, yellow, red healthStatusText: '未知', healthCode: '', reportTime: '', historyList: [] }, onLoad() { this.loadUserInfo(); this.loadLatestReport(); this.loadHistory(); }, loadUserInfo() { const userInfo = wx.getStorageSync('userInfo'); this.setData({ userInfo }); }, async loadLatestReport() { try { const res = await get('/reports/latest/'); this.setData({ healthStatus: res.health_status, healthStatusText: this.getStatusText(res.health_status), healthCode: res.code, reportTime: new Date(res.report_time).toLocaleString() }); } catch (error) { console.log('暂无健康记录或获取失败', error); this.setData({ healthStatusText: '暂无记录', reportTime: '-' }); } }, async loadHistory() { try { const res = await get('/reports/'); this.setData({ historyList: res.results || res }); // 根据分页调整 } catch (error) { console.error('获取历史失败', error); } }, getStatusText(status) { const map = { 'green': '绿码', 'yellow': '黄码', 'red': '红码', 'gray': '未知' }; return map[status] || '未知'; }, navigateToReport() { wx.navigateTo({ url: '/pages/report/report' }); }, refreshCode() { this.loadLatestReport(); wx.showToast({ title: '已刷新', icon: 'success' }); } });5.5 健康申报页面
申报页面 (pages/report/report) 用于提交新的健康信息。
<!-- pages/report/report.wxml --> <view class="container"> <form bindsubmit="submitReport"> <view class="form-item"> <text class="label">体温 (°C)</text> <input name="temperature" type="digit" placeholder="请输入体温" value="{{temp}}" /> </view> <view class="form-item"> <text class="label">是否有不适症状?</text> <switch name="hasSymptom" checked="{{hasSymptom}}" /> </view> <view class="form-item"> <text class="label">近期是否前往风险地区?</text> <switch name="recentTravel" checked="{{recentTravel}}" /> </view> <view class="tips"> 请如实填写,虚假信息将承担相应责任。 </view> <button formType="submit" type="primary" loading="{{loading}}">提交申报</button> </form> </view>// pages/report/report.js import { post } from '../../utils/request'; Page({ data: { temp: '36.5', hasSymptom: false, recentTravel: false, loading: false }, submitReport(e) { const formData = e.detail.value; const { temperature, hasSymptom, recentTravel } = formData; if (!temperature || isNaN(temperature)) { wx.showToast({ title: '请输入有效体温', icon: 'none' }); return; } this.setData({ loading: true }); const payload = { temperature: parseFloat(temperature), has_symptom: !!hasSymptom, recent_travel: !!recentTravel }; post('/reports/', payload) .then(res => { wx.showToast({ title: '申报成功', icon: 'success' }); setTimeout(() => { wx.navigateBack(); // 返回上一页 }, 1500); }) .catch(err => { console.error('申报失败', err); wx.showToast({ title: '申报失败', icon: 'none' }); }) .finally(() => { this.setData({ loading: false }); }); } });6. 系统运行与效果验证
6.1 启动Django后端服务
- 在项目根目录(
manage.py所在目录)执行数据库迁移,创建数据表:python manage.py makemigrations python manage.py migrate - 创建一个超级用户,用于访问Django Admin后台:
python manage.py createsuperuser - 启动开发服务器:
服务器启动后,你可以访问:python manage.py runserver 0.0.0.0:8000http://127.0.0.1:8000/admin/- Django管理后台(用超级用户登录)。http://127.0.0.1:8000/api/reports/- 浏览健康申报记录的API端点(需登录)。
6.2 配置并运行微信小程序
- 在微信开发者工具中打开你的小程序项目。
- 修改
utils/request.js中的BASE_URL,确保它是你Django服务器的IP和端口(例如http://192.168.1.100:8000/api)。注意:不能使用localhost,因为小程序运行在手机端模拟器,localhost指向手机自身。 - 在微信开发者工具的“详情”->“本地设置”中,勾选“不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书”。(这仅用于开发调试,上线前必须配置合法域名)。
- 点击“编译”,小程序将启动。首次加载会执行登录逻辑。
6.3 功能验证流程
- 登录验证:打开小程序,查看控制台(Console)是否有“登录成功”的日志,并检查本地存储是否有了
token和userInfo。 - 首页加载:首页应能显示用户头像/昵称。由于没有申报记录,健康状态可能显示“暂无记录”。
- 健康申报:点击“立即申报”进入申报页,填写信息并提交。成功后,应返回首页,并看到最新的健康状态和健康码(一串代码)。
- 数据查看:在电脑浏览器访问Django Admin (
http://127.0.0.1:8000/admin/),登录后应能在Api -> Health reports下看到刚提交的记录。 - API测试:可以使用Postman或浏览器直接访问
http://127.0.0.1:8000/api/reports/(需在Header中添加Authorization: Token <你的token>),查看返回的JSON数据。
7. 常见问题与排查思路
在开发过程中,你几乎一定会遇到下面这些问题。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| Django启动报错 | 端口被占用,依赖未安装,数据库错误。 | 查看命令行错误信息。 | 换端口(runserver 8001),检查pip list,运行python manage.py check。 |
| 小程序无法连接后端 | BASE_URL配置错误,后端服务未运行,网络问题。 | 1. 检查Django服务器是否运行。 2. 在浏览器直接访问 BASE_URL。3. 小程序开发工具检查网络请求。 | 确保IP和端口正确,关闭防火墙或杀毒软件,使用IP而非localhost。 |
| CORS跨域错误 | Django后端未正确配置CORS。 | 浏览器开发者工具Console查看错误,或Django日志。 | 1. 确认settings.py中CORS_ALLOW_ALL_ORIGINS = True(开发)。2. 确认 corsheaders应用和中间件已添加。 |
| 登录失败,无法获取openid | 小程序AppID/AppSecret错误,code无效或过期。 | 1. 打印微信接口返回的完整data。2. 检查微信公众平台AppID和AppSecret。 | 核对AppID/AppSecret,确保code是调用wx.login()实时获取的。 |
| API请求返回403(无权限) | 未携带Token或Token失效,视图权限设置问题。 | 1. 检查小程序请求Header是否有Authorization。2. 检查Django中该用户的Token是否存在。 | 1. 确保登录流程正确,Token被存储和携带。 2. 对于无需登录的API(如核验),在视图上加 @permission_classes([AllowAny])。 |
| Django Admin页面样式丢失 | 未收集静态文件或DEBUG=False。 | 访问Admin页面查看。 | 开发时保持DEBUG=True。部署时运行python manage.py collectstatic。 |
| 数据库操作报错 | 模型字段修改后未迁移,SQLite文件权限问题。 | 查看Django报错信息。 | 运行python manage.py makemigrations和python manage.py migrate。检查db.sqlite3文件权限。 |
8. 项目优化与进阶建议(毕业设计加分项)
一个能运行的Demo只是开始,要让项目脱颖而出,你需要考虑以下优化点:
- 更真实的健康码:使用
qrcode库在后端生成二维码图片,将code编码进去。小程序端展示该二维码图片,核验端扫码后解析。 - 更复杂的健康状态算法:引入更多维度(接触史、疫苗接种情况、核酸结果),并设计加权计算模型,而不仅仅是简单的if-else。
- 数据可视化:在管理后台或小程序内,使用图表(如ECharts)展示用户健康趋势、地区风险统计等。
- 权限精细化:区分普通用户、核验员、管理员。使用DRF的权限类实现,例如核验员只能访问核验接口。
- 缓存优化:用户最新的健康码状态可以被频繁查询,使用Django的缓存框架(如Redis)进行缓存,减轻数据库压力。
- 单元测试:为关键的模型、视图编写单元测试,这是工程化的重要体现。使用Django的
TestCase。 - 部署上线:尝试将项目部署到云服务器(如阿里云、腾讯云)。涉及Nginx、Gunicorn、域名、HTTPS配置等,是宝贵的实战经验。
- 文档与注释:为你的代码编写清晰的注释,并生成一份项目说明文档(README.md),介绍项目背景、技术栈、部署步骤和接口文档。
9. 总结:从项目到能力的跨越
通过这个“基于Django的本地健康宝微信小程序系统”的完整实现,你收获的远不止一份毕业设计源码。你实践了一个现代Web应用从数据库设计、API构建到前端交互的全流程,并解决了前后端分离、第三方登录(微信)、权限控制等核心问题。
这个项目的核心价值在于其模式的可复用性。你可以轻易地将“健康宝”替换成“图书管理”、“在线点餐”、“社区论坛”,其技术架构——Django REST Framework提供数据接口,微信小程序作为交互终端——是通用的。掌握了这个套路,你就有能力去承接更多类似的全栈需求。
在答辩或向他人展示时,重点阐述你的技术选型理由、数据库设计思路、API安全措施(如Token认证)以及遇到的挑战和解决方案。这比单纯演示功能更能体现你的技术深度。
最后,请记住,本文提供的代码是一个清晰的起点和范例。真正的学习发生在你根据自己需求修改、调试和扩展它的过程中。建议你立即动手,从搭建环境开始,一步步将系统跑起来,并在过程中不断提出“如果我要加XX功能,该怎么改?”的问题。
