宠物医院管理系统实战:Vue+Django前后端分离开发完整指南

发布时间:2026/10/4 4:31:07
宠物医院管理系统实战:Vue+Django前后端分离开发完整指南 如果你正在踩 Python 全栈的入门路前端选 Vue后端在 Django 和 Flask 之间来回纠结又听人反复推荐用 PyCharm 做开发工具那这个宠物医院管理系统项目几乎就是为你量身定做的完整样板。它不是一个被讲烂了的图书管理或学生管理系统而是带着真实业务场景的管理系统宠物档案、预约挂号、诊疗记录、药品库存、收费结算每个模块都踩在“管理系统开发”最典型的通用能力上。做一遍这个项目你基本就能摸清前后端分离开发的完整流程。这个项目最适合三类人一是正在准备毕业设计或课程设计的在校生需要一个功能完整、技术栈够看、演示效果好的系统二是想从前端或后端单端转向全栈的开发新人想用一个项目把 Vue 和 Django/Flask 串起来三是想给自己宠物店或小型诊所做一套内部管理工具的创业者虽然商用需要再打磨但拿来改改业务逻辑就能直接跑。我的建议是把整体方案定成“后端 Django 前端 Vue 开发工具 PyCharm”同时把 Flask 作为对照理解的对象。因为从这个项目的业务复杂度来看Django 自带的后台管理、ORM、认证体系和 DRF 扩展能让你少写大量重复代码。但如果你更喜欢把每个环节都自己掌控Flask 的写法我也会同步讲清楚。这套组合做完你对 Python Web 开发的上限和下限都会有一个非常直观的认知。1. 项目核心需求与功能模块拆解1.1 宠物医院管理系统的业务逻辑先别急着写代码把业务想清楚比什么都重要。宠物医院管理系统的核心是“以宠物为中心以诊疗为主线”围绕一只宠物从建档、预约、就诊、开药到结算的完整生命周期来设计功能模块。我翻过不少同类项目最常见的毛病就是把系统做成一个“增删改查大杂烩”功能堆了一堆但业务逻辑不闭环。比如能添加宠物档案但没办法把一次完整的就诊过程串起来能录药品信息但库存扣减逻辑完全缺失。所以你在这个项目里至少要保证以下几条业务链路是通的宠主注册登录后可以添加宠物档案、预约挂号、查看历史就诊记录前台收到预约后可以安排医生、调整预约状态医生接诊时可以填写诊断结果、开出处方处方关联药品和剂量收费员根据处方生成结算单同时扣减药品库存管理员可以管理员工账号、查看全院的经营统计数据这样的业务设计才是“管理系统”而不是“数据管理工具”。在做需求分析时建议你画一张简单的业务流转图理清每条链路涉及的表和状态变化后面写代码会顺畅很多。1.2 角色权限与功能清单系统至少要拆出三种角色宠主普通用户、医院员工医生/前台/收费员、系统管理员。不同角色看到的功能入口不同这是管理系统项目评分和实用性的关键分水岭也是面试时经常被追问的点。我给出一份可以直接抄的权限清单角色核心权限前端页面入口宠主注册登录、宠物档案管理增删改查、预约挂号、查看就诊历史和处方个人中心、我的宠物、在线预约医生查看预约列表、接诊/完成诊疗、填写病历、开处方工作台、诊疗管理、处方管理前台/收费员预约管理确认/取消、收费结算、打印小票预约管理、收费管理管理员员工账号管理、药品库存管理、基础数据维护、经营统计系统管理、员工管理、数据看板权限控制在后端用 Django 自带的 Group/Permission 体系就能做也可以直接用 is_staff、is_superuser 加自定义字段区分角色前端配合 Vue Router 的路由守卫控制页面访问权限。这个设计做完你的项目在“完整性”上已经超过大半同类作品。2. 技术选型深度解析2.1 Django 还是 Flask这道选择题怎么做很多人在技术选型上反复纠结其实思路很简单看你的系统是“业务重、类型多”还是“接口少、逻辑轻”。宠物医院管理系统属于典型的“业务重、表格多、权限复杂”的项目所以我首推 Django。Django 的杀手锏是它把 Web 开发中高频使用的东西全都内置了ORM 让你不用写原生 SQL 就能完成建表和查询Admin 后台能在开发阶段直接当数据管理界面用自带的认证系统处理登录注册和会话管理再加上 Django REST FrameworkDRF这个扩展前后端分离项目需要的序列化、视图集、路由自动生成、JWT 认证全都一站式解决。Flask 也不是不能用它更轻、更灵活适合你只想提供几个 API 接口、希望完全掌控代码结构的小项目。如果你用 Flask 做这个系统数据库操作用 SQLAlchemy 或直接写原生 SQL序列化用 Flask-RESTX 或手工 dict 转换登录认证用 Flask-JWT-Extended。代码量会比 Django 多出不少但你会对 HTTP 请求处理、ORM 映射、中间件机制理解得更透彻。我的结论是追求开发效率和完整性选 Django追求学习深度和灵活性选 Flask。这篇博文以 Django 为主线Flask 的差异点我会在关键环节标注出来。2.2 为什么前端一定要用 VueVue 在这个项目里的价值不在于它比 React 或者原生 JS 好多少而在于它带来了一套“组件化 数据驱动”的开发思维。管理后台这类界面有大量的表格、弹窗、表单、状态切换用 Vue 组件写一遍后面复用的时候你会真切感受到组件化的威力。我建议用 Vue 3 Element Plus Vite 的组合。这套组合是当前 Vue 生态里开发管理后台效率最高的搭配Element Plus 提供了现成的表格、表单、弹窗、日期选择器、分页等组件你不用自己从头写 UIVite 启动速度快热更新体验比 Webpack 时代好太多。用 Vue 的时候你还会强烈感受到一个概念前端只管“数据渲染和用户交互”后端只管“数据和业务逻辑”。前端拿到后端返回的 JSON 数据更新 data 里的变量页面自动同步刷新这个体验是 jQuery 时代完全无法想象的。重要的是在使用 Vue 的过程中掌握这几个核心知识点组件通信props 和 emit或 Pinia 全局状态、Vue Router 的嵌套路由和路由守卫、Axios 的封装与拦截器。2.3 PyCharm 在开发流程中的真实价值关于 PyCharm很多人只把它当编辑器用浪费了它一半的价值。在处理这个项目的过程中PyCharm 真正帮你省时间的地方有三个第一虚拟环境管理。PyCharm 创建项目时可以自动创建 venv 虚拟环境为每个项目隔离 Python 依赖包避免你电脑上的包互相污染。这对 Django 项目尤为重要因为 Django、DRF、corsheaders 这些包的版本冲突会让你的项目莫名其妙的报错。第二调试器是真神器。在 Django 视图函数、DRF 序列化器这一层打断点用 Step Into 逐行看 HTTP 请求在代码里怎么流动、数据怎么被序列化、ORM 查询返回了什么结果这些理解靠 print 是做不到的。你能直观看到 request 对象长什么样、ORM 查询集是如何惰性求值的对理解框架底层的帮助极大。第三内置的数据库工具。PyCharm 的 Database 面板直接连上 MySQL 或 SQLite可以直观地看表结构、执行 SQL 查询、甚至可视化地编辑表格数据。联调前端时很多“接口返回数据不对”的问题在数据库面板里一眼就能发现是数据本身就录错了还是代码查错了。Flask 项目在 PyCharm 里同样可以一键配置运行配置设置环境变量、调试模式、端口号。所以无论你最终选哪个后端框架PyCharm 都是非常值得投入时间去熟悉的工具。3. 系统架构与数据库设计3.1 前后端分离架构的请求流转开发这个项目你首先要理解前后端分离的请求流转模型。前端项目和后端项目是两个完全独立的进程各自部署在不同端口开发阶段 Vue 默认 5173Django 默认 8000通过 HTTP 接口通信前端处理 UI 与交互后端处理数据与业务。请求流转的完整过程可以理解为用户在浏览器打开 Vue 页面页面中的 Axios 发起 HTTP 请求到后端接口地址后端 Django 的 URL 路由接收到请求转发给对应的视图函数或 DRF 视图集视图层通过序列化器对请求参数进行校验通过 ORM 操作数据库完成业务逻辑后端返回 JSON 格式的响应数据前端拿到后更新页面状态这个架构带来的直接好处是前后端可以并行开发、独立部署、分别扩展也是目前企业实际开发中最主流的模式。开发阶段最大的坑是跨域问题因为前后端端口不同浏览器会拦截跨域请求解决办法是在 Django 中安装 django-cors-headers 配置允许的源或者在前端 Vite 配置文件里设置开发代理把/api开头的请求转发到后端地址。这两个方法后面都会讲。3.2 数据表设计决定系统上限的设计环节数据库设计是整个项目的灵魂。一个业务逻辑清晰的管理系统表关系一定是清晰的。我给出核心表的设计完全可以直接用。用户表用 Django 内置的auth.User扩展一个Profile模型存放手机号、角色类型宠主/医生/前台/管理员、头像、所属医院等字段。好处是复用 Django 自带的密码加密、Session、权限系统不用自己重造轮子。宠物档案表包含宠物名称、品种、性别、出生日期、体重、毛色、绝育状态、疫苗记录可以用一个关联表做多对多、主人外键关联到用户表。这里要注意的是宠物和主人的关系是一对多一只宠物只能有一个主人一个主人可以有多只宠物。预约表关联宠物、关联医生员工、预约日期与时间段、状态待确认/已确认/已完成/已取消、病情描述。状态流转是管理系统的重点前端按钮要根据当前状态动态变化。诊疗记录表关联预约或直接关联宠物和医生记录主诉、诊断结果、医嘱、下次复诊日期。诊疗记录一旦生成就不允许修改所以历史数据要留痕。药品表与处方表药品表保存药品名称、规格、库存量、单价、生产厂家、有效期。处方单作为中间表关联诊疗记录和药品还要有处方明细表或直接在处方单字段里存 JSON记录每种药品的用法用量和数量。每次开处方时后端要同步执行库存扣减操作。收费表关联预约或诊疗记录包含项目费用诊疗费、化验费、药费等、总金额、支付方式微信/支付宝/现金/会员卡、收费时间。这些表建好后用 Django 的 ORM 把它们定义成模型类跑makemigrations和migrate就能自动生成数据库表。遇到过不少新手在这一步报错多数是模型类没有正确注册到 INSTALLED_APPS或者外键关联写错了字段名。3.3 接口风格与返回格式统一前后端分离项目的沟通语言是 JSON。为了让前端同事或者你自己写前端时不至于疯掉接口返回格式一定要统一。我常用的返回格式是{ code: 200, message: success, data: { id: 1, name: 豆豆, breed: 泰迪 } }这个格式在 DRF 中可以通过自定义响应函数来实现也可以在序列化器返回中统一包一层公共方法。前端 Axios 封装里响应拦截器拿到code 200就返回data否则弹出message提示用户。这样前后端的协作方式在大型团队中已经成为一种通用约定你趁早养成这种习惯后续做任何接口对接都会收益。分页是管理系统的另一个重要接口规范。列表接口不要一次性返回所有数据要用 DRF 的分页类限制每页的数据量。比如每页 10 条前端表格组件会根据总条数自动生成分页器用户翻页时前端携带page参数重新请求当前页的数据。这个交互模式几乎每个管理后台都有必须熟练掌握。4. 后端核心模块实操拆解4.1 环境准备与项目初始化开始写代码之前先把环境配好。我用的是 Python 3.10 版本Django 选择 4.2 LTS 版本它是目前生产环境最稳定的。安装命令很简单pip install django4.2 pip install djangorestframework pip install django-cors-headers pip install djangorestframework-simplejwt pip install mysqlclient # 如果用 MySQLWindows 下可能需要下载 whl 安装如果你用的是 Flask对应安装flask、flask-sqlalchemy、flask-restx、flask-jwt-extended。虚拟环境强烈建议用 PyCharm 创建项目时默认生成的venv后续所有依赖都在项目隔离环境里避免全局环境污染。创建 Django 项目和应用django-admin startproject pet_hospital cd pet_hospital python manage.py startapp pets python manage.py startapp appointments python manage.py startapp medical python manage.py startapp drugs python manage.py startapp billing按业务模块拆分 app比把所有内容塞在一个 app 里更容易维护。每个 app 内部仍然是 models.py、views.py、serializers.py 的标准结构DRF 项目通常还会在项目根目录建一个 utils 模块存放公共函数和自定义响应类。4.2 模型定义与 ORM 查询要点下面给出宠物档案的模型定义示例这是整张核心表的骨架from django.db import models from django.contrib.auth.models import User class Pet(models.Model): GENDER_CHOICES ( (M, 公), (F, 母), ) name models.CharField(宠物名, max_length50) breed models.CharField(品种, max_length50) gender models.CharField(性别, max_length1, choicesGENDER_CHOICES) birthday models.DateField(出生日期, nullTrue, blankTrue) weight models.FloatField(体重(kg), default0) color models.CharField(毛色, max_length50, blankTrue) sterilized models.BooleanField(是否绝育, defaultFalse) owner models.ForeignKey(User, on_deletemodels.CASCADE, verbose_name主人, related_namepets) created_at models.DateTimeField(创建时间, auto_now_addTrue) class Meta: db_table pet verbose_name 宠物档案 verbose_name_plural verbose_name def __str__(self): return f{self.owner.username}的{self.name}ORM 查询里有几个点需要特别注意比如按联合条件查询最近预约、按外键反向关联查询某宠主的所有宠物用owner request.user就可以直接过滤当前登录用户的宠物列表。这是前后端分离项目中权限隔离的重要环节如果不加这个过滤任何用户直接访问/api/pets/?owner1就能看到别人的宠物数据了。Django 的 ORM 查询集是惰性的只有当你迭代它或者对切片操作时才会真正执行 SQL 语句。学会用select_related和prefetch_related来优化外键关联查询避免 N1 查询问题即先查一次列表再对每一条记录逐一查关联表。对比两个查询的性能差异会有很深印象。按热词里提到的“django 执行查询-删除对象”补充一点删除对象时要注意外键关联数据的处理。比如删除一个宠物档案时它关联的预约和诊疗记录怎么办我建议业务上采用软删除增加一个is_active字段删除时置为 False而不是用物理删除这样数据审计时有迹可循。Django 的on_deletemodels.CASCADE会级联删掉子表数据用的时候要格外小心。4.3 序列化器与视图集编写DRF 里序列化器负责把 ORM 对象转成 JSON以及校验前端传入的参数。宠物档案的序列化器这么写from rest_framework import serializers from .models import Pet class PetSerializer(serializers.ModelSerializer): owner_name serializers.CharField(sourceowner.username, read_onlyTrue) age serializers.SerializerMethodField() class Meta: model Pet fields [id, name, breed, gender, birthday, age, weight, color, sterilized, owner, owner_name, created_at] read_only_fields [owner, created_at] def get_age(self, obj): from datetime import date if obj.birthday: today date.today() return today.year - obj.birthday.year - ( (today.month, today.day) (obj.birthday.month, obj.birthday.day) ) return None def create(self, validated_data): validated_data[owner] self.context[request].user return super().create(validated_data)视图集使用ModelViewSet直接获得增删改查全部接口再配合 DRF 的DefaultRouter自动生成 URL 路由from rest_framework.viewsets import ModelViewSet from rest_framework.permissions import IsAuthenticated from .models import Pet from .serializers import PetSerializer class PetViewSet(ModelViewSet): queryset Pet.objects.all() serializer_class PetSerializer permission_classes [IsAuthenticated] def get_queryset(self): user self.request.user if user.is_staff: return Pet.objects.all() return Pet.objects.filter(owneruser)这样写完成了一个模块的全部后端接口。如果你是 Flask 项目这一步就稍微麻烦一点需要手动定义一个蓝图编写api/pets的 GET/POST 路由再在路由函数里调用 SQLAlchemy 查询和数据校验。对比之后你会更理解为什么说 Django 是“全家桶式”的框架。4.4 用户认证与权限控制宠物医院系统涉及不同角色必须使用 JWT 做身份认证。Django 推荐用djangorestframework-simplejwt配置登录接口后前端登录成功会拿到access_token和refresh_token然后前端把access_token存到 localStorage每次请求时通过 Axios 拦截器在请求头里带上Authorization: Bearer token。代码关键配置如下# settings.py REST_FRAMEWORK { DEFAULT_AUTHENTICATION_CLASSES: ( rest_framework_simplejwt.authentication.JWTAuthentication, ), DEFAULT_PERMISSION_CLASSES: ( rest_framework.permissions.IsAuthenticated, ), }URL 路由里加上from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView urlpatterns [ path(api/token/, TokenObtainPairView.as_view(), nametoken_obtain_pair), path(api/token/refresh/, TokenRefreshView.as_view(), nametoken_refresh), ]角色权限则通过自定义权限类BasePermission子类来判断。比如医生才能创建诊疗记录、前台才能操作收费单都需要在视图集permission_classes里自定义。实际上更优雅的做法是给用户分组把权限授予 Group这样每个用户只要加进对应分组就具有了该角色的全部权限。这个机制在企业级项目里是标配。4.5 药品库存扣减与收费结算的事务处理宠物医院管理系统里最体现专业性的一点就是多条业务数据需要同时更新这时必须使用数据库事务。开一张处方时系统要在同一事务里完成三件事创建处方记录、扣减药品库存、可能生成待支付账单。如果其中任意一步因为库存不足或数据校验失败而报错整个操作都要回滚不能让药品库存扣了但处方没生成。Django 中可以用transaction.atomic()实现from django.db import transaction class PrescriptionService: staticmethod def create_prescription(doctor, medical_record, drug_items): with transaction.atomic(): prescription Prescription.objects.create( medical_recordmedical_record, doctordoctor, ) for item in drug_items: drug Drug.objects.select_for_update().get(iditem[drug_id]) if drug.stock item[quantity]: raise DrugShortageError(f药品 {drug.name} 库存不足) drug.stock - item[quantity] drug.save() PrescriptionItem.objects.create( prescriptionprescription, drugdrug, quantityitem[quantity], dosageitem[dosage] ) return prescription这里的select_for_update()尤其关键它会在数据库层面锁定读取的行防止两个医生同时处理同一张处方时并发扣减库存出现负数。这也是后端开发中“并发安全”意识的重要基础。如果项目里遇到扣减库存后数值对不上多半就是没有处理好并发问题。5. 前端核心模块实操拆解5.1 Vue 3 项目初始化与依赖安装前端部分我用 Vite Vue 3 Element Plus Pinia Vue Router Axios这是目前最主流的管理后台技术栈。Vue 项目脚手架创建npm create vitelatest pet-web -- --template vue cd pet-web npm install npm install element-plus axios vue-router4 pinia npm install element-plus/icons-vue npm install sass -D初始化项目后先把 Element Plus 完整引入到入口文件main.js再用到哪个组件按需引入也可以但为了开发速度我先完整引入等熟悉后再优化体积。Vite 项目的结构比 Vue 2 时期的 Webpack 项目更干净关键目录包括src/views页面组件、src/router路由配置、src/storePinia 状态管理、src/api请求接口封装、src/components通用组件。5.2 路由配置与登录权限守卫前端路由配置是管理系统界面的骨架。我用一套干净的路由配置方案把路由分成两个层级公开路由如登录页/首页以及需要登录后才能访问的业务路由角色权限再通过 Meta 元信息控制。import { createRouter, createWebHistory } from vue-router const routes [ { path: /login, name: Login, component: () import(/views/Login.vue), meta: { public: true } }, { path: /, component: () import(/layout/Index.vue), redirect: /dashboard, children: [ { path: dashboard, name: Dashboard, component: () import(/views/Dashboard.vue), meta: { title: 工作台, roles: [admin, doctor, receptionist] } }, { path: pets, name: Pets, component: () import(/views/Pets.vue), meta: { title: 宠物档案, roles: [admin, doctor, owner] } } ] } ]全局前置守卫通过判断 token 是否存在以及用户角色是否在允许列表中来控制页面跳转router.beforeEach((to, from, next) { const token localStorage.getItem(access_token) if (to.meta.public) { next() } else if (!token) { next(/login) } else { // 判断角色权限这里读取 Pinia 中保存的角色信息 const userRole store.userInfo.role if (to.meta.roles !to.meta.roles.includes(userRole)) { next(/dashboard) // 无权限跳回首页 } else { next() } } })这一步实现了页面级别的权限控制。热词里提到的 Vue 动态路由本质上是后端根据用户角色返回菜单列表前端用router.addRoute()动态添加路由表。如果做了动态权限你就不用在路由表里写死所有页面而是后端返回菜单配置前端动态渲染侧边栏。那种方案更贴近真实企業项目但复杂度也成倍上升建议先把静态路由做熟练再考虑。5.3 Axios 封装与接口联调Axios 的位置相当于前端与后端沟通的“电话接线员”请求前自动带上 token响应后自动处理错误码。封装思路如下import axios from axios import { ElMessage } from element-plus import router from /router const request axios.create({ baseURL: /api, timeout: 10000 }) // 请求拦截器带上 JWT token request.interceptors.request.use(config { const token localStorage.getItem(access_token) if (token) { config.headers.Authorization Bearer ${token} } return config }) // 响应拦截器统一处理错误码 request.interceptors.response.use( response { const res response.data if (res.code ! 200) { ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) } return res.data }, error { if (error.response?.status 401) { ElMessage.error(登录已过期请重新登录) router.push(/login) } else { ElMessage.error(error.response?.data?.message || 网络异常) } return Promise.reject(error) } ) export default request每个业务模块的接口再单独建一个 API 文件。比如src/api/pet.jsimport request from /utils/request export const getPetList (params) request.get(/pets/, { params }) export const createPet (data) request.post(/pets/, data) export const updatePet (id, data) request.put(/pets/${id}/, data) export const deletePet (id) request.delete(/pets/${id}/)开发阶段的跨域代理配置在vite.config.js里export default defineConfig({ plugins: [vue()], server: { port: 5173, proxy: { /api: { target: http://127.0.0.1:8000, changeOrigin: true } } } })这样前端请求/api/pets/时Vite 开发服务器会自动把请求转发到 Django 的 8000 端口避免浏览器层面的跨域拦截问题。生产环境部署时则通过 Nginx 配置反向代理把/api路径转发到后端服务逻辑是一模一样的。5.4 组件化开发与业务页面实现前端页面组件化开发以“宠物档案”页面为例一个完整的列表页由搜索区、表格区、分页器、弹窗表单四个部分组成拆成PetList.vue、PetFormDialog.vue等组件父组件负责持有数据子组件通过 props 接收数据、通过 emit 通知父组件刷新。关键代码逻辑template div classpet-page el-card shadownever el-form inline el-form-item label宠物名称 el-input v-modelqueryParams.keyword placeholder搜索宠物名/品种 clearable / /el-form-item el-form-item el-button typeprimary clickloadData查询/el-button el-button typesuccess clickopenDialog()新增宠物/el-button /el-form-item /el-form el-table :datapetList v-loadingloading border stripe el-table-column propname label宠物名 / el-table-column propbreed label品种 / el-table-column propgender label性别 / el-table-column propweight label体重(kg) / el-table-column propowner_name label主人 / el-table-column label操作 template #default{ row } el-button link typeprimary clickopenDialog(row)编辑/el-button el-button link typedanger clickhandleDelete(row)删除/el-button /template /el-table-column /el-table el-pagination v-model:current-pagequeryParams.page :page-sizequeryParams.page_size :totaltotal layouttotal, prev, pager, next current-changeloadData / /el-card /div /templateElement Plus 的el-table通过prop字段名自动渲染数据配合v-loading指令和分页组件一个完整的管理后台列表页本体就完成了。在这个基础上套上弹窗表单表单校验、提交接口就能实现增删改查。前端写完后你会明显感觉到管理后台的界面开发速度几乎 80% 被 Element Plus 接管工作量主要集中在业务逻辑的组织和数据流转的编排上。这正是组件化开发的核心收益通用能力交给组件库业务能力自己写。6. 联调与部署阶段的关键经验6.1 前后端联调时的高频问题排查拿一套页面和数据在一个浏览器里跑起来时经常出现的联调问题基本都是几类问题可能原因解决方案前端请求 404路由没配置、接口地址前缀不对检查 Django 的 urls.py 和前端 proxy 配置跨域报错后端没有配置允许源用 django-cors-headers 配置或前端代理401 未认证token 没带或已过期检查 Axios 拦截器确认 token 是否写入请求头500 服务器错误后端代码异常查看 PyCharm 控制台完整 traceback数据列表不对权限过滤或分页参数问题在 Django 视图集打断点检查get_queryset我实际开发中最常踩的一个坑是前端明明把 token 存到了 localStorage但刷新页面后 Pinia 里用户信息丢失导致路由守卫把用户踢回登录页。解决方法是刷新页面后在App.vue或路由守卫里根据 token 调一个/api/users/me/接口重新拉取当前用户信息再存进 Pinia。这个细节很多新手会漏掉但几乎所有管理系统都会遇到。6.2 本地部署与简单发布开发完成后先在本地产物环境跑通整个流程。前端构建npm run build构建后dist目录就是纯静态文件HTML/CSS/JS。最简单的部署方案是后端 Django 用 gunicorn 启动监听某个端口前端 dist 目录用 Python 内置的 http.server 或者其他静态服务器启动配置好 CORS 后两个服务就能互相通信。更正式的生产环境则用 Nginx 托管前端静态文件并把/api请求反向代理给 gunicorn。需要注意一个细节Django 的 DEBUG 在生产环境必须设为 False同时要收集静态文件并配置ALLOWED_HOSTS否则页面能打开但样式丢失或直接报错。如果你用的是 Flask部署时用 gunicorn 加flask run的生产版本配置完静态文件目录即可。6.3 数据库选型开发用 SQLite上线换 MySQL开发调试阶段直接用 Django 默认的 SQLite零配置、文件型数据库点点鼠标就能建表对本地开发很友善。但商用或者毕业设计答辩要演示大量数据时建议换成 MySQL。切换方法很简单在settings.py中改数据库配置然后重新执行makemigrations和migrate再导入测试数据即可。换 MySQL 时最容易出问题的点一是字符集必须设置成utf8mb4否则中文会乱码二是时间时区问题Django 的USE_TZ True时 MySQL 连接要配置好时区参数。这两个问题我当年各踩过一次现在只要换库就会检查这几项配置。7. 常见问题与排查技巧实录7.1 环境与依赖篇Pycharm 里 import django 标红大概率是解释器没用对你没选择虚拟环境里的 Python导致 Pycharm 使用的是全局解释器看不到虚拟环境中的包。看右下角解释器配置选择项目.venv/bin/python即可解决。pip 安装慢、超时国内网络下建议配置镜像源如清华 PyPI 镜像一次性把速度问题根治后面所有 pip install 都会快很多。npm install 卡住同样用镜像源方案NPM 官方源在国外访问慢换淘宝镜像后安装依赖的体验会有质的飞跃。Django 启动后提示ModuleNotFoundError: No module named django问题不是没安装而是你启动时用了虚拟环境外的python命令先激活虚拟环境或者直接用 Pycharm 的运行配置。7.2 代码逻辑篇makemigrations 时提示没有模型变化检查模型所在的 app 是否在INSTALLED_APPS中注册。经常见到 app 文件已经创建但忘记注册的情况。序列化器报错Field id expected a number but got xxx通常是前端传参类型不对比如字符串1和数字1的差异建议在序列化器里加上类型转换和校验。用 ORM 查询时出现重复数据多表关联查询时缺少distinct()通常出现在跨外键过滤的列表接口上。Django 的 ORM 在 JOIN 后会返回笛卡尔积需要.distinct()去重。前端表格刷新数据没更新Vue 3 已经比 Vue 2 少了很多响应式坑但如果你直接修改一个嵌套对象的新增属性而不重新赋值整个对象页面依然不会响应。用reactive时注意整个数据流的更新方式。7.3 数据与业务篇删除宠物后预约记录全空了因为外键用了CASCADE删除主表会级联删除关联数据。如果不希望这样外键加PROTECT或SET_NULL同时配合软删除的方案。药品库存扣成负数并发情况下没有加锁或者前端连续点击按钮导致重复提交。后端加select_for_update()行锁前端增加按钮 loading 的防重复点击。登录后访问接口仍然 401检查 token 的携带方式JWT 必须是Authorization: Bearer token格式很多新手大小写或空格写错导致认证失败。收费单总金额与处方金额对不上收费总额应该是根据处方明细动态计算的前端只能展示不能直接传来一个总额让后端存。后端在生成收费单时自动汇总处方明细金额。8. 后续扩展与实际使用建议如果你做完这套系统还有余力可以考虑以下几个方向的扩展方向一种是增加消息通知功能预约状态变化、诊疗结果出来时通过 WebSocket 或简单的轮询推送给宠主提升系统的实时性和体验。一种是增加数据可视化看板用 ECharts 在首页展示营收趋势、各科室接诊量、药品消耗排行、宠物品种分布等图表这类统计功能能在演示和面试时显著提升观感。一种是接入支付功能对接微信支付或支付宝的沙箱环境让宠主在线支付诊疗费和药费支付结果回调后自动更新收费单状态。这一步接触的是真实项目里商业闭环的完整链路。如果想让这个项目真正在自己的宠物诊所里用起来建议先从预约排班管理做起让前台和医生先养成使用习惯再逐步把库存、结算等模块业务数据跑起来。实际场景中对数据准确性要求很高所以我建议每次上线新模块前做一轮完整的测试数据录入排查流程是否顺畅再交付。如果用这个项目写简历建议把重点放在“业务闭环”上能清楚讲出你如何设计权限、如何保证库存并发安全、如何通过事务确保数据一致性这些远比“我会 Vue 和 Django”更有含金量。就我个人经验而言面试官最喜欢听到的恰恰是你在开发中踩过坑之后对架构和业务逻辑的反思这些实践经验是书本上很难学到的。最后分享一个受用很久的习惯每次开发完一个功能模块把浏览器、后端控制台、数据库三个界面同时打开做一次完整的端到端流程测试。比如从注册一个宠主账号、添加宠物、预约医生、医生填写病历、开出处方、前台收费到管理员看到统计数据全链路走一遍你会在三分之二的位置发现很多自己想不到的问题。这个项目对我来说最大的价值也正在于此它让我真正理解了前后端分离的系统是如何像一个完整的组织一样协作运转的。当你亲手把一个模块一个模块串成完整可用的系统时那种对整个开发流程的掌控感是任何教程都无法替代的。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询