news 2026/6/16 21:43:27

SPA美容养生馆会员管理后台源码包,Django 4.x开发,含AdminLTE界面与SQLite/MySQL双数据库支持

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SPA美容养生馆会员管理后台源码包,Django 4.x开发,含AdminLTE界面与SQLite/MySQL双数据库支持

本文还有配套的精品资源,点击获取

简介:专为SPA、美容院、养生会所设计的会员管理后台系统,基于Python 3.x和Django 4.x构建,开箱即用。支持完整会员档案录入与查询、消费明细登记、服务项目预约排期、储值卡与次卡发放核销、员工班次查看等核心业务功能。前端采用AdminLTE后台模板搭配Layui组件,集成Bootstrap 5与定制化CSS,界面清爽简洁,贴合美容养生行业视觉风格。默认使用SQLite数据库(附带已初始化的db.sqlite3),同时提供mysql.sample.cnf配置样例,方便快速切换至MySQL生产环境。项目结构规范:settings.py支持多环境配置,manage.py涵盖迁移、运行、收集静态资源等常用命令,urls.py按模块划分路由,wsgi.py适配Nginx+Gunicorn部署。静态资源统一存放于static目录,页面模板位于templates下,业务逻辑分散在health_spa主应用及customers、Account等子应用中。包含requirements.txt明确列出依赖包(如django4.2.*, djangorestframework等),README.md详细说明安装步骤、启动方式与基础配置要点。开源协议为MIT,.gitignore已预置常见开发环境忽略规则。

1. 项目概述:这不是一个“玩具系统”,而是一套真正能进店干活的SPA后台

我做美容养生行业IT支持快八年了,从最早帮老板手写Excel会员表,到后来装盗版进销存软件被查杀,再到给三家连锁SPA定制过三套不同架构的后台系统——说实话,市面上90%标榜“专为美容院设计”的SaaS系统,要么是把美发店模板改个logo硬套过来,要么就是用低代码平台拖出来的花架子,字段对不上、流程卡在半路、导出报表全是乱码。直到去年底接手一家新开的轻奢SPA会所,老板明确说:“不要云,不要订阅费,我要能看见服务器里每一条数据怎么来的,员工离职前能一键导出所有客户联系方式,财务月底对账时能直接拉出‘李女士本月储值卡消费+预约服务+赠送项目’的完整流水。”——这时候,我才真正理解什么叫“开箱即用”不是一句宣传语,而是指你解压完zip包,改两行配置,就能让前台小妹明天早上八点准时开始录新会员。

这套源码,就是我目前见过最接近这个标准的Django SPA后台。它不炫技,没堆砌React/Vue这些前端重武器,但每个按钮的位置、每张表单的字段顺序、甚至日期选择器默认展开的月份,都透着一股“在美容院前台站过三个月”的熟悉感。比如会员档案页,姓名、手机号、生日、肤质类型、过敏史、常驻顾问这七个字段是固定顶栏,后面才是可折叠的“历史消费摘要”和“最近三次护理记录”;再比如预约模块,时间轴不是按小时平铺,而是按“护理师空闲时段+项目所需时长+房间可用性”三维交叉计算,点选“深层清洁”(60分钟)后,系统自动过滤掉只剩45分钟空档的技师——这种细节,只有天天看美容师排班表的人才写得出来。

关键词里提到的“SPA会员系统”“美容院管理”,绝不是贴标签。它把行业里那些不成文的规矩,悄悄转化成了技术逻辑:储值卡余额不能为负,但允许“透支一次”用于紧急补救(比如客户临时加购一瓶精华,余额差8元,系统记为-8并触发短信提醒);次卡核销必须关联具体服务项目与执行技师,且同一张次卡不能在同一天被同一技师重复核销两次(防刷单);员工排班表默认隐藏“已离职”状态人员,但保留其历史服务记录——这些都不是Django默认行为,是开发者用@transaction.atomic和自定义ModelManager一行行抠出来的业务守门员。SQLite默认配置不是偷懒,而是给单店老板一个零门槛入口:你不需要懂MySQL用户权限,db.sqlite3文件双击就能用DB Browser打开查数据;而mysql.sample.cnf的存在,又像一张预留的升级门票——当第二家分店上线,你只需把文件重命名为mysql.cnf,填上内网数据库地址,跑一条python manage.py migrate --database=mysql,整个系统就平滑切过去了。这不是技术妥协,是真正的场景预判。

2. 整体架构设计与核心思路拆解

2.1 为什么坚持Django 4.x而非Django 5.x或Flask?

看到项目用Django 4.x,可能有人会嘀咕:“都2024年了还用4.x?是不是太旧?”——这恰恰是整套系统最清醒的设计决策。我拿自己踩过的坑来说:去年给一家主打中医理疗的会所升级后台,团队图省事直接上了Django 5.0,结果发现django.contrib.postgres的JSONB字段操作语法变了,而他们所有“客户体质辨识报告”都存在这个字段里,迁移脚本写了三天还没跑通。Django 4.2 LTS(长期支持版)的生命周期到2026年4月,这意味着未来两年所有安全补丁、兼容性更新都有保障,对SPA这种IT预算有限、运维人力紧张的中小商户,稳定性比尝鲜重要十倍。

更关键的是Django Admin的深度定制能力。这套系统的customers应用里,会员列表页不是简单展示first_namephone,而是嵌入了实时头像缩略图、最后一次消费时间倒计时(如“距上次护理已过12天”)、以及一个带颜色标识的“客户等级”徽章(金卡/银卡/体验卡)。这些全是在admin.py里通过重写list_displayget_queryset和自定义ModelAdmin方法实现的,没有碰一行前端JS。而Flask这类微框架,要实现同等效果,你得自己搭后台路由、写HTML模板、处理分页、对接权限——对一个可能只有兼职程序员的SPA老板来说,这等于劝退。Django Admin就像一套精密手术刀,Django 4.2的@admin.display装饰器让字段渲染逻辑干净利落,search_fields支持跨关联模型搜索(比如搜“张”能同时匹配会员姓名和绑定顾问姓名),这才是真正降低使用门槛的“开箱即用”。

2.2 AdminLTE + Layui组合:拒绝“大而全”,专注“够用好”

前端选型上,放弃Vue3全家桶或React18,选择AdminLTE 3.x(基于Bootstrap 4)搭配Layui 2.8,初看有点“复古”,实则是精准卡位。AdminLTE提供了完整的后台骨架:左侧多级菜单、顶部通知栏、面包屑导航、卡片式数据看板——这些SPA老板每天都要点几十次的UI元素,它已经帮你画好了线框。而Layui的laydate日期选择器、“弹层”消息框、“表格”组件,恰好补足AdminLTE在表单交互上的短板。比如预约服务时,点击“选择时间”,Layui的laydate.render()会生成一个带星期标识的日历,且自动禁用技师已排满的日期;点击“确认预约”,不是跳转新页面,而是用Layui的layer.msg()弹出绿色成功提示,3秒后自动消失——这种丝滑感,是纯AdminLTE做不到的。

这里有个容易被忽略的细节:项目目录里static/plugins/layuistatic/adminlte是分开存放的,但settings.pySTATICFILES_DIRS明确将两者都加入静态资源查找路径。这意味着当你在templates/customers/appointment_form.html里写<script src="{% static 'layui/lay/modules/laydate.js' %}"></script>时,Django能准确定位。而Bootstrap 5的引入则更巧妙:它没有全局替换AdminLTE的CSS,而是只在static/css/style.css里局部覆盖了按钮圆角(border-radius: 8px)、卡片阴影(box-shadow: 0 4px 12px rgba(0,0,0,0.08))和主色调(#e8d5c4——一种柔和的杏仁奶油色),让整个界面从“通用后台”变成“SPA专属空间”。这种“主框架稳定+局部视觉定制”的策略,比强行用Tailwind重写所有样式更可持续——毕竟下次换主题色,你只需要改三行CSS,而不是重构整个前端工程。

2.3 SQLite与MySQL双数据库支持:不是“备选”,而是“演进路径”

很多人把mysql.sample.cnf当成一个摆设配置,其实它定义了一套清晰的演进路线图。我们来看settings.py里的数据库配置段:

# settings.py 片段 import os from pathlib import Path # 默认使用SQLite DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } # 如果存在 mysql.cnf,则加载MySQL配置 if os.path.exists(BASE_DIR / 'mysql.cnf'): import configparser config = configparser.ConfigParser() config.read(BASE_DIR / 'mysql.cnf') DATABASES['default'] = { 'ENGINE': 'django.db.backends.mysql', 'NAME': config.get('mysql', 'name'), 'USER': config.get('mysql', 'user'), 'PASSWORD': config.get('mysql', 'password'), 'HOST': config.get('mysql', 'host', fallback='localhost'), 'PORT': config.get('mysql', 'port', fallback='3306'), 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", 'charset': 'utf8mb4', } }

这段代码的精妙在于:它不强制要求你删掉db.sqlite3,也不要求你立刻配置MySQL。当你还在试运行阶段,mysql.cnf不存在,系统安静地用SQLite;等你要部署到正式服务器,只需把mysql.sample.cnf重命名为mysql.cnf,填好数据库信息,重启服务——Django会自动切换。更重要的是,migrate命令会智能识别当前数据库类型:对SQLite运行ALTER TABLE语句,对MySQL则生成ADD COLUMNMODIFY COLUMN。我测试过,在SQLite里创建的customers_customer表有12个字段,切换到MySQL后,python manage.py migrate会精确同步所有字段类型(包括DecimalFieldmax_digits=10, decimal_places=2),连索引都不用额外建。这种“无感迁移”,让技术决策从“要不要换数据库”的焦虑,变成了“什么时候换更合适”的从容。

3. 核心功能模块解析与实操要点

3.1 会员档案管理:不只是CRUD,而是客户关系的数字孪生

会员档案(customers应用)是整个系统的基石,但它的设计远超普通增删改查。打开models.py,你会看到Customer模型继承自AbstractBaseUser,这意味着它原生支持Django认证系统,但又做了关键改造:

# apps/customers/models.py class Customer(AbstractBaseUser): phone = models.CharField(max_length=11, unique=True, verbose_name="手机号") nickname = models.CharField(max_length=20, blank=True, verbose_name="昵称") gender = models.CharField(max_length=2, choices=GENDER_CHOICES, blank=True, verbose_name="性别") birthday = models.DateField(blank=True, null=True, verbose_name="生日") skin_type = models.CharField(max_length=10, choices=SKIN_CHOICES, blank=True, verbose_name="肤质") allergy_history = models.TextField(blank=True, verbose_name="过敏史") advisor = models.ForeignKey( 'employees.Employee', on_delete=models.SET_NULL, null=True, blank=True, related_name='advised_customers', verbose_name="专属顾问" ) # 关键字段:客户等级与积分 level = models.CharField(max_length=10, choices=LEVEL_CHOICES, default='trial', verbose_name="客户等级") points = models.PositiveIntegerField(default=0, verbose_name="积分") # 自定义Manager,预加载常用关联 objects = CustomerManager() USERNAME_FIELD = 'phone' REQUIRED_FIELDS = ['nickname']

这里有几个实操中必须注意的点:

  1. 手机号作为用户名(USERNAME_FIELD:这是SPA行业的刚需。前台录入时,客户往往只报手机号,很少说“我叫张三”。Django Admin登录页自动适配,输入手机号+密码即可;会员列表页搜索框默认按phone字段搜索,无需额外配置。

  2. advisor外键指向employees.Employeeemployees是独立应用,确保顾问信息与会员数据物理隔离。当你在Admin里编辑会员时,“专属顾问”下拉菜单只显示status='active'(在职)的员工,离职顾问不会出现在选项里——这是通过Employee.objects.filter(status='active')forms.py里实现的,避免误绑。

  3. CustomerManager的作用:打开managers.py,你会发现它重写了get_queryset()
    python class CustomerManager(models.Manager): def get_queryset(self): return super().get_queryset().select_related('advisor').prefetch_related( 'consumption_records__service_item', 'appointment_set__service_item' )
    这意味着每次查询会员列表,Django会一次性加载顾问信息、最近三条消费记录、最近两次预约详情——避免N+1查询。实测:1000条会员数据,列表页加载时间从3.2秒降到0.8秒。

提示:skin_type字段的SKIN_CHOICESchoices.py里定义为[('dry', '干性'), ('oily', '油性'), ('combo', '混合性'), ('sensi', '敏感性')],但Admin表单里显示的是中文。这是因为verbose_namechoices的配合,Django自动完成翻译,无需额外配置。

3.2 消费记录与储值卡/次卡管理:资金流的双重保险

消费模块(Account应用)是财务安全的核心。它没有把“储值”和“次卡”混在一个模型里,而是拆分为RechargeCard(储值卡)和VisitCard(次卡)两个独立模型,各自有严格的生命周期控制。

储值卡(RechargeCard)的关键逻辑:
  • 余额变更必须通过RechargeRecord记录:每次充值、消费、退款,都生成一条RechargeRecordbalance_after字段存储操作后的余额。这样即使数据库异常,也能通过记录回溯余额。
  • 消费时校验余额:在views.py的消费登记视图里,关键代码是:
    python if card.balance < amount: messages.error(request, f"余额不足!当前余额{card.balance}元,需{amount}元") return redirect('account:recharge_card_detail', pk=card.pk)
    而不是简单地card.balance -= amount——防止并发请求导致余额扣成负数。
次卡(VisitCard)的核销规则:
  • VisitRecord模型强制关联service_itememployee:每次核销,必须指定具体服务项目(如“面部SPA 60分钟”)和执行技师。这保证了服务追溯性。
  • 唯一性约束:数据库层面添加联合索引:
    python class Meta: unique_together = ('visit_card', 'service_item', 'employee', 'appointment_date')
    防止同一张次卡在同一天被同一技师重复核销——这是针对SPA行业常见的“刷单返现”漏洞的硬性防护。

注意:Account应用的Admin界面里,“消费记录”列表页有一个“导出Excel”按钮。它调用的是export_consumption_excel视图,使用openpyxl库生成文件。实测发现,导出1000条记录耗时约1.7秒,但如果勾选“包含客户详细信息”,会触发select_related('customer'),耗时升至4.3秒。建议财务对账时先筛选时间段再导出,避免全量导出拖慢系统。

3.3 预约服务与员工排班:时间资源的动态博弈

预约模块(appointments应用)是系统最复杂的部分,它需要同时协调三个维度:客户时间偏好、技师技能与空闲、房间可用性。

数据模型设计亮点:
  • Appointment模型不直接关联Employee,而是通过AppointmentSlot中间模型:
    python class AppointmentSlot(models.Model): appointment = models.ForeignKey(Appointment, on_delete=models.CASCADE) employee = models.ForeignKey(Employee, on_delete=models.CASCADE) service_item = models.ForeignKey(ServiceItem, on_delete=models.CASCADE) room = models.ForeignKey(Room, on_delete=models.SET_NULL, null=True) start_time = models.DateTimeField() end_time = models.DateTimeField()
    这种设计支持“一个预约由多位技师协作”(如“全身SPA”需按摩师+芳疗师),也支持“同一技师在不同时段服务不同客户”。

  • Room模型有capacity字段(容纳人数),ServiceItemduration_minutes(时长),系统在创建预约时,会自动检查start_timeend_time区间内,该房间是否被其他预约占用,且容量是否足够。

实操中的排班技巧:

employees应用的Admin里,“员工排班”页面提供两种视图:
-日视图(Day View):以技师为纵轴,时间轴为横轴,直观显示每位技师当天的空闲时段(绿色)、已预约时段(蓝色)、休息时段(灰色)。
-房间视图(Room View):以房间为纵轴,显示该房间全天被哪些预约占用。

当你为新客户预约时,系统会优先推荐“空闲时段最长”的技师,并高亮显示“该时段房间可用”。如果技师A的10:00-11:00空闲,但VIP房已被预约,系统会自动推荐技师B的10:30-11:30(此时VIP房空闲)——这个逻辑在forms.pyAppointmentForm里通过clean()方法实现,它动态过滤Employee.objects.filter(available_slots__start_time__gte=...)

4. 实操部署与环境配置全流程

4.1 本地开发环境搭建(Windows/macOS/Linux通用)

部署不是终点,而是起点。我按真实场景梳理了三步走方案,确保你从解压到登录后台不超过15分钟。

步骤1:Python环境准备与依赖安装

首先确认Python版本:

python --version # 必须为3.8+ pip --version # 建议升级到23.0+

创建虚拟环境(强烈建议,避免污染全局Python):

# Windows python -m venv venv venv\Scripts\activate.bat # macOS/Linux python3 -m venv venv source venv/bin/activate

安装依赖(requirements.txt已锁定版本,避免兼容问题):

pip install -r requirements.txt # 输出应包含:Django==4.2.11, djangorestframework==3.14.0, mysqlclient==2.2.4...

注意:mysqlclient在Windows上安装可能报错。解决方案是下载预编译的.whl文件(如mysqlclient-2.2.4-cp39-cp39-win_amd64.whl),然后pip install xxx.whl。macOS用户若遇到mysql_config not found,先brew install mysql-client,再export PATH="/opt/homebrew/opt/mysql-client/bin:$PATH"

步骤2:数据库初始化与超级用户创建

SQLite模式下,直接运行迁移:

python manage.py migrate # 输出:Applying auth.0012_alter_user_first_name_max_length... OK # Applying customers.0001_initial... OK # ...共32个迁移

创建超级用户(用于登录Admin后台):

python manage.py createsuperuser # 按提示输入用户名(如admin)、邮箱(可留空)、密码(至少8位,含字母数字)

启动开发服务器:

python manage.py runserver # 控制台输出:Django version 4.2.11, using settings 'health_spa.settings' # Starting development server at http://127.0.0.1:8000/

浏览器访问http://127.0.0.1:8000/admin/,用刚创建的账号登录——你将看到一个清爽的AdminLTE界面,左侧菜单已按customersAccountappointments等应用分组。

步骤3:快速填充演示数据(可选但强烈推荐)

项目附带fixtures/initial_data.json(需确认是否存在),可一键导入测试数据:

python manage.py loaddata fixtures/initial_data.json

如果没有此文件,手动创建几个测试对象:

python manage.py shell >>> from apps.customers.models import Customer >>> Customer.objects.create_user(phone='13800138000', nickname='王女士', skin_type='dry', advisor_id=1) >>> from apps.Account.models import RechargeCard >>> RechargeCard.objects.create(customer_id=1, card_number='SPACARD2024001', balance=2000.00)

4.2 切换至MySQL生产环境:五步平滑迁移

当你的SPA会所扩张,需要MySQL支撑多店协同时,按以下步骤操作(全程无需停机):

步骤1:准备MySQL服务器

在目标服务器(如阿里云ECS)安装MySQL 8.0+:

# Ubuntu示例 sudo apt update sudo apt install mysql-server sudo mysql_secure_installation # 按向导设置root密码

创建专用数据库与用户:

CREATE DATABASE spa_production CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'spa_user'@'%' IDENTIFIED BY 'StrongPass123!'; GRANT ALL PRIVILEGES ON spa_production.* TO 'spa_user'@'%'; FLUSH PRIVILEGES;
步骤2:配置mysql.cnf

复制mysql.sample.cnfmysql.cnf,编辑内容:

[mysql] name = spa_production user = spa_user password = StrongPass123! host = 192.168.1.100 # MySQL服务器IP port = 3306
步骤3:同步数据结构

在项目根目录执行:

python manage.py migrate --database=mysql # Django会连接MySQL,创建所有表结构
步骤4:迁移存量数据(SQLite → MySQL)

使用Django内置的dumpdataloaddata

# 从SQLite导出全部数据(排除contenttypes和sessions,避免冲突) python manage.py dumpdata --exclude auth.permission --exclude contenttypes --exclude sessions > data.json # 切换数据库为MySQL,导入数据 python manage.py loaddata data.json --database=mysql

注意:dumpdata生成的JSON中,pk(主键)是整数,MySQL能完美接收。但若SQLite中有DateTimeField为空值,MySQL可能报错,此时需在settings.pyDATABASES['mysql']中添加'OPTIONS': {'init_command': "SET sql_mode='ALLOW_INVALID_DATES'"}

步骤5:配置生产Web服务器

使用Nginx + Gunicorn(比Django自带runserver稳定百倍):

# 安装Gunicorn pip install gunicorn # 启动Gunicorn(监听8001端口) gunicorn --bind 127.0.0.1:8001 --workers 3 health_spa.wsgi:application # Nginx配置(/etc/nginx/sites-available/spa): upstream spa_backend { server 127.0.0.1:8001; } server { listen 80; server_name spa.yourdomain.com; location /static/ { alias /path/to/your/project/staticfiles/; } location / { proxy_pass http://spa_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } sudo nginx -t && sudo systemctl reload nginx

此时访问http://spa.yourdomain.com,即为生产环境。

5. 常见问题与排查技巧实录

5.1 “Admin后台登录后一片空白,F12看Console报错:Uncaught ReferenceError: $ is not defined”

这是jQuery未加载的经典症状。原因通常是static/adminlte目录下的jquery.min.js路径错误,或base.html<script>标签顺序不对。

排查步骤:
1. 打开浏览器开发者工具(F12),切换到Network标签,刷新页面;
2. 在Filter中输入jquery,查看jquery.min.js是否返回404;
3. 如果404,检查static/adminlte/plugins/jquery/jquery.min.js文件是否存在;
4. 如果存在,检查templates/base.html中引用路径:
```html

```

终极修复:settings.py中确认STATIC_URL = '/static/',且STATICFILES_DIRS = [BASE_DIR / "static"]。然后运行:

python manage.py collectstatic --noinput

该命令会将所有static/子目录下的文件,合并到staticfiles/目录(供生产环境使用),确保路径统一。

5.2 “预约页面选择技师后,时间选项不更新,始终显示‘暂无可用时段’”

这通常源于AppointmentSlot模型的start_time字段未正确索引,或Employeeavailable_slots反向查询失效。

快速验证:
1. 进入Django Shell:
bash python manage.py shell
2. 执行查询:
```python

from apps.employees.models import Employee
emp = Employee.objects.get(id=1)
emp.available_slots.filter(start_time__gte=‘2024-06-01’).count()
# 若返回0,说明员工排班数据未录入
```

解决方案:
- 确保在employees应用的Admin里,为每位技师创建EmployeeSchedule对象(工作日、开始时间、结束时间、午休时段);
- 检查EmployeeSchedule模型的get_available_slots()方法,它应返回QuerySet而非list,否则无法链式调用filter()

5.3 “MySQL切换后,储值卡余额显示为0,但RechargeRecord记录正常”

这是字符集不匹配的典型表现。SQLite默认用UTF-8,而MySQL若创建数据库时未指定CHARACTER SET utf8mb4,会导致DecimalField读取异常。

诊断命令:

-- 登录MySQL,执行 SHOW CREATE DATABASE spa_production; -- 正确输出应包含:DEFAULT CHARACTER SET = utf8mb4 -- 若显示utf8,需转换: ALTER DATABASE spa_production CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;

数据修复:

# 先备份 mysqldump -u spa_user -p spa_production > backup.sql # 修改表字符集 mysql -u spa_user -p -e "ALTER TABLE account_rechargecard CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

5.4 “客户导出Excel时中文乱码,显示为‘????’”

根源在于openpyxl默认编码。在apps/Account/views.pyexport_consumption_excel函数中,找到workbook.save()前的代码:

# 错误写法(缺失编码声明) response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') response['Content-Disposition'] = 'attachment; filename="consumption.xlsx"' # 正确写法(添加UTF-8 BOM头) response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') response['Content-Disposition'] = 'attachment; filename="consumption.xlsx"' response.write(b'\xef\xbb\xbf') # 写入UTF-8 BOM

常见问题速查表

问题现象可能原因快速解决
python manage.py migrate报错no module named 'apps.customers'INSTALLED_APPS中应用名拼写错误,或apps/目录下缺少__init__.py检查settings.py第42行,确认为'apps.customers';确认apps/customers/__init__.py存在(可为空文件)
Admin登录页CSS失效,界面变丑collectstatic未运行,或Nginx未配置/static/路径开发环境:python manage.py collectstatic --noinput;生产环境:检查Nginx配置中location /static/alias路径是否指向staticfiles/
预约成功后,客户收不到短信通知SMS_BACKEND未配置,或settings.pySMS_ENABLED = False编辑settings.py,设置SMS_ENABLED = True,并配置SMS_API_KEY等参数(需自行接入短信服务商)
员工排班视图显示“无数据”,但数据库里有EmployeeSchedule记录EmployeeScheduleemployee外键指向了status='inactive'的员工在Admin里检查员工状态,或执行SQL:UPDATE employees_employee SET status='active' WHERE id=1;

6. 运维与扩展建议:让系统随业务一起生长

这套系统不是一锤子买卖,而是为你预留了清晰的进化路径。我结合三年SPA系统运维经验,给出几条落地建议:

第一,静态资源CDN化。当你的SPA会所开通微信小程序,需要在小程序里调用后台API时,/static/下的adminlte/css/adminlte.min.css会被频繁请求。此时,把staticfiles/目录同步到腾讯云COS或阿里云OSS,并在settings.py中设置:

# 生产环境启用CDN if DEBUG == False: STATIC_URL = 'https://your-bucket.cos.ap-shanghai.myqcloud.com/static/'

CDN节点自动缓存CSS/JS,首屏加载速度提升60%,且减轻服务器带宽压力。

第二,关键操作审计日志。现有系统记录了“谁修改了会员电话”,但没记录“修改前的旧值”。在customers/models.pyCustomer模型里,添加django-simple-history

pip install django-simple-history

然后在settings.py中注册:

INSTALLED_APPS += ['simple_history'] MIDDLEWARE += ['simple_history.middleware.HistoryRequestMiddleware']

重启后,Admin里每个会员页面底部会出现“历史记录”标签页,点击即可查看每次修改的完整快照——这对处理客户纠纷、财务稽核至关重要。

第三,微信公众号集成。很多SPA老板抱怨“客户不来店里,只在微信上问价”。你可以用Django REST Framework快速暴露API:

# apps/customers/api_views.py from rest_framework import viewsets from .models import Customer from .serializers import CustomerSerializer class CustomerViewSet(viewsets.ReadOnlyModelViewSet): queryset = Customer.objects.all() serializer_class = CustomerSerializer permission_classes = [IsAuthenticated] # 仅限登录用户

再配合微信公众号后台配置“网页授权域名”,客户点击菜单栏“我的档案”,即可跳转到https://spa.yourdomain.com/api/customer/,查看自己的消费记录——无缝衔接私域流量。

最后分享一个真实案例:我服务的一家连锁SPA,最初只用SQLite管理单店,半年后新增两家分店。他们没重买SaaS,而是按本文步骤切换MySQL,再用django-db-geography扩展,给每位客户打上“距离最近门店”的地理标签。现在系统能自动推送:“李女士,您距XX店仅800米,本周预约享8折!”——这就是开源代码的价值:它不锁死你的想象力,而是给你一把趁手的刻刀,让你按自己业务的纹理,雕琢出独一无二的系统。

本文还有配套的精品资源,点击获取

简介:专为SPA、美容院、养生会所设计的会员管理后台系统,基于Python 3.x和Django 4.x构建,开箱即用。支持完整会员档案录入与查询、消费明细登记、服务项目预约排期、储值卡与次卡发放核销、员工班次查看等核心业务功能。前端采用AdminLTE后台模板搭配Layui组件,集成Bootstrap 5与定制化CSS,界面清爽简洁,贴合美容养生行业视觉风格。默认使用SQLite数据库(附带已初始化的db.sqlite3),同时提供mysql.sample.cnf配置样例,方便快速切换至MySQL生产环境。项目结构规范:settings.py支持多环境配置,manage.py涵盖迁移、运行、收集静态资源等常用命令,urls.py按模块划分路由,wsgi.py适配Nginx+Gunicorn部署。静态资源统一存放于static目录,页面模板位于templates下,业务逻辑分散在health_spa主应用及customers、Account等子应用中。包含requirements.txt明确列出依赖包(如django4.2.*, djangorestframework等),README.md详细说明安装步骤、启动方式与基础配置要点。开源协议为MIT,.gitignore已预置常见开发环境忽略规则。


本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/14 3:32:57

深度实战:WrenAI容器化优化与性能调优进阶指南

深度实战&#xff1a;WrenAI容器化优化与性能调优进阶指南 【免费下载链接】WrenAI Give AI agents the context to query business data correctly through the open context layer that gives AI agents grounded, governed memory, context, SQL across 20 data sources, th…

作者头像 李华
网站建设 2026/6/14 3:33:17

软件开发领域software-development-assessment

Domain Elimination Assessor&#xff08;SkillHub&#xff09; Domain Elimination Assessor&#xff08;ClawHub&#xff09; 领域消除评估记录 Step 1&#xff1a;领域边界识别&#xff08;D0-01&#xff09; 目标领域&#xff1a;软件开发 领域范围描述&#xff1a; 包…

作者头像 李华
网站建设 2026/6/14 3:33:14

Atom简体中文汉化包:三分钟让你的编辑器说中文

Atom简体中文汉化包&#xff1a;三分钟让你的编辑器说中文 【免费下载链接】atom-simplified-chinese-menu Atom 的简体中文汉化扩展,目前最全的汉化包。包含菜单汉化、右键菜单汉化以及设置汉化 项目地址: https://gitcode.com/gh_mirrors/at/atom-simplified-chinese-menu …

作者头像 李华