恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Python Django影楼管理系统实战:从需求分析到预约排期与订单流转
首页
资讯中心
/
Python Django影楼管理系统实战:从需求分析到预约排期与订单流转
Python Django影楼管理系统实战:从需求分析到预约排期与订单流转
发布时间:2026/9/26 6:21:57
上个月帮一位开影楼的朋友做了一套管理系统基于python的婚纱影楼服务平台从需求确认到上线跑通大概用了三周。说实话这个项目没有多少高深算法但把影楼的预约、排期、订单状态、客户跟进这些琐碎业务梳理清楚比写代码本身更花精力。这里把整个设计思路、核心代码实现和踩过的坑完整记一遍。如果你正在学Python想找个能写进简历的真实项目或者准备帮传统门店做数字化转型这篇内容应该能派上用场。1. 影楼管理的真实痛点为什么需要一套服务平台1.1 一个工作日下午的混乱场面我朋友那家影楼开在二线城市规模算中等6个摄影师、4个化妆师、一个300平的内景棚外加合作的几个外景基地。听起来团队不小但每周一的下午店里都像在打仗。前台小妹一边接电话一边翻纸质预约本微信群里客户在问下周六还能排吗摄影师在群里喊我那天拍不了要去外地参加婚礼销售手里攥着四五张定金收据不知道对应哪个订单。旺季的时候更夸张有个客户提前一个月付了定金结果到了拍摄前一天才发现档期和另一组客户重了最后只能赔礼道歉加免费加急损失了一单利润还丢了口碑。这个场景其实不是个例。影楼行业的业务链路比普通零售店长得多咨询、探店、试纱、付定金、定档期、拍摄、选片、精修、交付每一步都可能跨几天甚至几周。信息一旦散落在纸质本、微信聊天记录、销售个人手机里就一定会出乱子。当朋友找我聊这事的时候我第一反应是问他你现在最痛的是什么他说了两个词撞档、跟丢。撞档是预约排期问题跟丢是客户跟进问题。这两个痛点恰好就是一套信息管理系统最擅长解决的。1.2 业务链条上的信息断点把影楼的完整业务链画出来大概是这样一个流程客户通过大众点评、小红书或者熟人介绍找过来销售微信沟通约到店探店看样片确定套餐付定金约定拍摄日期拍摄当天化妆加拍摄一周后选片然后进入修图环节最后取件交付。这个链条里几乎每一环都有信息断点。客户资料在销售的微信好友列表里套餐价格在店长的Excel表里拍摄档期在纸质预约本上修图进度在修图师的电脑文件夹里交付记录在微信转账记录里。各个环节之间全靠人肉传递来一个新前台要现学一个星期才能上手店长想看一眼本月业绩还得等销售晚上手工汇总。这些断点带来的直接后果就是客户体验差、内部协作扯皮、管理层看不到数据。而且影楼行业还有一个特殊性它的产品是服务时间档期一旦空出来或者被浪费就是实打实的损失不像卖货还能存仓库。1.3 平台要覆盖的完整业务链路所以这套系统最基本的目标就很明确了把上面那条完整的业务链路串起来。具体拆成模块就是客户管理、套餐管理、摄影师与排期、预约管理、订单状态跟踪、统计报表六块。客户管理解决跟丢问题所有咨询过的客户都进系统销售离职也带走不了排期和预约解决撞档问题摄影师档期全部数据库化冲突直接代码阻挡订单状态跟踪解决现在到哪一步了的问题客户问进度不用再转三个群统计报表让店长能一眼看到本月签了多少、摄影师谁拍得多。明确这些之后你就会发现这个项目本质上是一个典型的信息管理系统。它没有推荐算法、没有图像识别就是表单、状态、列表、统计的组合。明确了这一点技术选型的路就走对了一半。2. 技术选型Python Django 为什么是这个项目的正解2.1 三类方案的对比当时摆在面前的其实是三个方向。第一个是用现成的SaaS影楼管理系统市面上有但朋友这家店有特殊需求门店加外景基地、三组不同风格的摄影团队还要求数据能独立分析SaaS系统定制起来很麻烦按月付费长期算也不便宜。第二个方向是用Java Spring Boot生态成熟稳定但说实话就这个体量的系统Spring Boot那一套配置写起来太啰嗦一个人开发三周根本拿不下来。第三个方向就是Python加Django。为什么最终选了它我列了一个简单的对比表维度Java Spring BootNode.js ExpressPython Django开发效率中配置繁琐高但自由度过高很高约定优于配置自带后台无需另写无需另写自带AdminORM成熟度中低高复杂查询顺手部署运维较重轻中等招人维护难一般相对容易Django最大的优势在于影楼业务几乎全是标准的增删改查而Django的Model-Admin设计天生就是为这类业务准备的。一个Admin后台配下来店长要看的客户列表、订单状态、摄影师排班半个运营后台就出来了开发量直接砍半。2.2 ORM 和 Admin 带来的开发效率变化很多人搜Python是冲着爬虫、数据分析、量化去的但实际在做这类管理型项目时Django的ORM和Admin才是真正省时间的地方。举一个很常见的查询场景销售想筛三月份之后咨询的、预算在一万到两万之间、还没有完成拍摄的客户。这个需求在Django里用ORM写非常直接。from django.db.models import Q from datetime import date customers Customer.objects.filter( created_at__date__gtedate(2024, 3, 1), budget__range(10000, 20000) ).filter( Q(orders__status__in[OrderStatus.DEPOSIT_PAID, OrderStatus.SHOOT_DONE]) | Q(orders__isnullTrue) ).distinct().select_related(last_order)Q对象组合条件、select_related避免查询数据库的次数翻倍这两招在处理客户-订单这种一对多关系时特别常用。Django的ORM把SQL层复杂的JOIN和条件组合封装得足够舒适又不至于像一些全自动框架那样让你失去对查询的控制。另外Django自带Admin后台这件事在这个项目里省了巨量时间。像影楼这种内部管理系统很多运营功能其实不需要精美前端一个能筛选、能搜索、能查看详情、能编辑状态的表格就够了。把核心模型注册进Admin配置一下list_display和list_filter店长就能直接上手用了。2.3 Redis 和 Celery小系统也需要异步虽然说了这是个小系统但有两个场景是同步代码搞不定的短信提醒和定时任务。客户拍摄前一天要收到提醒短信选片后两周没选完要提醒精修超时要通知店长这些都需要在后台定时跑任务。所以我引入了Redis加Celery的组合。Redis作为消息中间件Celery负责执行异步任务和周期任务。这里完全没有用什么高深的架构就是一个Celery Beat定时调度加上几个shared_task装饰的异步函数。后面会展开讲具体实现。3. 数据模型设计先把影楼的实体关系理清楚3.1 五张核心表的定义数据模型是整个系统的地基这块如果设计得不合理后面写业务逻辑会非常痛苦。影楼业务的实体关系其实很清晰客户预约摄影师客户购买套餐生成订单订单包含状态流转。核心表有五张Customer客户、Photographer摄影师、Package套餐、Appointment预约、Order订单。Django模型大致如下。from django.db import models from django.conf import settings class Customer(models.Model): name models.CharField(客户姓名, max_length50) phone models.CharField(手机号, max_length11, uniqueTrue) wechat models.CharField(微信号, max_length100, blankTrue) budget models.DecimalField(预算, max_digits10, decimal_places2, default0) source models.CharField(来源渠道, max_length20, choices[(dazhong, 大众点评), (xiaohongshu, 小红书), (friend, 朋友介绍), (walkin, 到店)]) remark models.TextField(备注, blankTrue) created_at models.DateTimeField(创建时间, auto_now_addTrue) class Photographer(models.Model): name models.CharField(姓名, max_length50) phone models.CharField(手机号, max_length11) style models.CharField(擅长风格, max_length50) max_shoots_per_day models.PositiveIntegerField(每日最大拍摄组数, default3) class Package(models.Model): name models.CharField(套餐名称, max_length100) price models.DecimalField(价格, max_digits10, decimal_places2) photos_count models.PositiveIntegerField(精修张数) studio_hours models.FloatField(棚内时长, default4) outdoor models.BooleanField(是否含外景, defaultFalse) class Appointment(models.Model): SLOT_CHOICES [(morning, 上午), (afternoon, 下午), (evening, 傍晚)] STATUS_CHOICES [(pending, 待确认), (confirmed, 已确认), (done, 已完成), (cancelled, 已取消)] customer models.ForeignKey(Customer, on_deletemodels.PROTECT) photographer models.ForeignKey(Photographer, on_deletemodels.PROTECT) date models.DateField(拍摄日期) slot models.CharField(时段, max_length10, choicesSLOT_CHOICES) status models.CharField(状态, max_length10, choicesSTATUS_CHOICES, defaultpending) class Meta: constraints [ models.UniqueConstraint( fields[photographer, date, slot], nameuniq_photographer_date_slot ) ] class Order(models.Model): customer models.ForeignKey(Customer, on_deletemodels.PROTECT) package models.ForeignKey(Package, on_deletemodels.PROTECT, nullTrue, blankTrue) status models.IntegerField(订单状态, default1) total_amount models.DecimalField(订单金额, max_digits10, decimal_places2) paid_amount models.DecimalField(实收金额, max_digits10, decimal_places2, default0) created_at models.DateTimeField(创建时间, auto_now_addTrue)这里有两个设计细节值得说一下。第一是外键的on_delete全部用了PROTECT。影楼的数据讲究留痕客户订单一不能删删了账对不上二不能用CASCADE级联删一个客户删掉连带删掉订单这种事在业务上就是事故。PROTECT保证有子记录存在时父记录删不掉逼着你用标记作废而不是物理删除来处理问题。第二是Appointment这个唯一约束。photographer加date加slot三者唯一意味着同一个摄影师同一天同一个时段只能有一个预约这个约束是后面档期冲突检测的数据库层面兜底。为什么必须加这个约束下一节细讲。3.2 订单状态的生命周期设计订单状态是影楼系统的灵魂。一开始我图省事直接在Order表里放一个status字段然后所有地方都硬编码数字判断。写了两天就发现问题状态在代码里散落得到处都是改一个数字都不知道影响哪里。后来老老实实定义状态常量集中放在一个模块里。class OrderStatus: CONFIRMED 1 # 已下单待付定金 DEPOSIT_PAID 2 # 定金已付 SHOOT_DONE 3 # 拍摄完成 SELECTING 4 # 选片中 RETOUCHING 5 # 精修中 READY 6 # 待交付 DONE 7 # 已完成 CANCELLED 0 # 已取消一个订单的完整生命周期是这样的状态值含义触发动作操作角色1已下单待付定金销售录入订单前台/销售2定金已付财务确认收款财务3拍摄完成摄影师上传拍摄记录摄影师4选片中客户到店选片或在线选片客户/选片师5精修中确定精修张数并提交修图选片师6待交付修图完成待客户取件修图师7已完成客户确认收货前台0已取消退款或放弃订单店长状态不能随意跳转。比如从1待付定金直接跳到3拍摄完成就不合理必须经过2。这个约束在代码里要显式判断不能靠前端按钮控制。3.3 时间字段的时区陷阱这个坑我必须单独拿出来讲因为第一次上线的时候就栽在这里了。Django默认的TIME_ZONE是UTC而影楼的预约提醒、档期排期全部依赖本地日期。如果设置不对服务器记录的时间会比北京时间慢8小时。当时有个客户凌晨三点收到了明天下午14点拍摄的提醒短信直接把前台电话打爆了。一查原因服务器用的UTC时间定时任务在UTC时间的某个点去算明天算出来的和本地日历差了一天。后来统一改成Asia/Shanghai并且代码里所有拿今天的操作都用timezone.localdate()只有存时间戳才让Django自动处理。from django.utils import timezone today timezone.localdate() tomorrow today timedelta(days1) appointments Appointment.objects.filter(datetomorrow, statusconfirmed)4. 预约排期冲突检测系统里最难写的一环4.1 档期模型怎么定义预约排期是整个系统最核心的业务逻辑也是影楼老板最关心的功能。设计档期模型的时候我纠结过一阵子是按小时拆还是按天拆按小时拆看起来自由度高但操作太繁琐前台选个时段要低下身子慢慢点日历而且摄影师化妆师是一个团队不是单独一个人在服务按小时排没法把团队资源统一约束。按天拆又太粗一个摄影师一天只接一组客户旺季资源浪费很严重。最后选了一个中间方案一天拆成上午、下午、傍晚三个时段。影楼的实际拍摄节奏上午档通常是棚内拍主纱下午档去外景傍晚档拍夕阳或夜景。一场完整的拍摄全程四到六小时三个时段的颗粒度正好对应行业习惯。档期的数据结构不需要额外的表就是在Appointment表里加一个slot字段。数据库约束就是3.1节里那个unique_together实际上用的是UniqueConstraint保证同一个摄影师、同一天、同一个时段只能存在一条有效预约。4.2 冲突检测的函数实现数据库约束能保证不出现重复数据但业务层还是要提前给用户一个友好的提示不能等到数据库抛异常才报错。所以我在创建预约时写了一个检测函数。from django.db.models import Q def check_slot_available(photographer_id, date, slot, exclude_appointment_idNone): 检查某个摄影师在某天某时段是否可预约 qs Appointment.objects.filter( photographer_idphotographer_id, datedate, slotslot ).filter( Q(statuspending) | Q(statusconfirmed) ) if exclude_appointment_id: qs qs.exclude(idexclude_appointment_id) return not qs.exists()一个关键细节查询时要排除掉cancelled状态的记录。已取消的预约不占档期如果不过滤掉会出现一个摄影师当天明明有空档却因为一条历史取消记录而约不上的问题。业务层检测之余我还要考虑一种情况摄影师每天最大拍摄组数。上午下午傍晚三个时段理论上就是三组但如果某个摄影师的max_shoots_per_day设成2那就还要额外校验当天已有预约数。这个逻辑可以在同一个函数里扩展不过大多数情况下三个时段本身就等于三个组数上限所以可以按需取舍。4.3 并发下的小概率事件用锁解决业务层检测完数据库约束也加上了理论上冲突问题已经解决。但还有一个小概率事件两个前台同时操作或者客户在线自助约同一个时段两个人同时通过了check_slot_available然后同时create这时候数据库唯一约束会拦下其中一个抛IntegrityError。如果不处理这个异常用户看到的就是一个500错误页。正确做法是把创建预约包在事务里加上行锁。from django.db import transaction, IntegrityError def create_appointment(customer_id, photographer_id, date, slot): with transaction.atomic(): locked_rows Appointment.objects.select_for_update().filter( photographer_idphotographer_id, datedate, slotslot ).filter( Q(statuspending) | Q(statusconfirmed) ) if locked_rows.exists(): raise ValueError(该时段已被预约请选择其他时段) return Appointment.objects.create( customer_idcustomer_id, photographer_idphotographer_id, datedate, slotslot, statusconfirmed )select_for_update会在数据库层面锁住匹配的行另一个事务只能等当前事务提交后才会执行查询。对于这种量级的管理系统性能完全够用。加了行锁之后业务层冲突检测、数据库唯一约束、事务锁三层防护档期这块基本就稳了。5. 订单流转与消息通知让每个角色都心里有数5.1 状态变更的约束与操作日志订单状态不能一改就完事。最初我把Order表里的status字段直接更新结果两周后出了问题客户投诉说精修还没好但系统里状态已经变成了待交付。一查发现是前台妹子操作时选错了下拉框。这就暴露了一个问题状态值直接赋值没有约束错改无痕。后来补了两样东西。第一是状态流转校验不允许跳状态和不合法变更第二是操作日志表每次状态变更都留一条记录。class OrderStatusLog(models.Model): order models.ForeignKey(Order, on_deletemodels.CASCADE, related_namestatus_logs) from_status models.IntegerField() to_status models.IntegerField() operator models.ForeignKey(settings.AUTH_USER_MODEL, nullTrue, on_deletemodels.SET_NULL) created_at models.DateTimeField(auto_now_addTrue)状态变更统一走一个函数禁止到处直接写status字段。def change_order_status(order, new_status, operator, allow_transitionsNone): if not allow_transitions: allow_transitions { OrderStatus.CONFIRMED: [OrderStatus.DEPOSIT_PAID, OrderStatus.CANCELLED], OrderStatus.DEPOSIT_PAID: [OrderStatus.SHOOT_DONE, OrderStatus.CANCELLED], OrderStatus.SHOOT_DONE: [OrderStatus.SELECTING], OrderStatus.SELECTING: [OrderStatus.RETOUCHING], OrderStatus.RETOUCHING: [OrderStatus.READY], OrderStatus.READY: [OrderStatus.DONE], } if new_status OrderStatus.CANCELLED and order.paid_amount 0: raise ValueError(订单已收款取消需要店长权限单独审批) if new_status not in allow_transitions.get(order.status, []): raise ValueError(f不允许从 {order.status} 变更到 {new_status}) OrderStatusLog.objects.create( orderorder, from_statusorder.status, to_statusnew_status, operatoroperator ) order.status new_status order.save(update_fields[status])操作日志表的价值在于任何时候都能回答这个订单是谁、在什么时候、把状态从哪改到哪的问题。客户投诉的时候不用吵架直接查流水。5.2 用 Celery 做预约提醒影楼每天最怕客户忘了来拍空档一上午就是几千块的成本。所以预约提醒是刚需。我的方案是每天固定时间跑一次任务把第二天的预约全部扫一遍给客户和摄影师分别发提醒。Celery加Django的写法很标准。先配置好broker用Redis然后定时任务用Celery Beat的crontab触发。# settings.py CELERY_BROKER_URL redis://localhost:6379/0 CELERY_TIMEZONE Asia/Shanghai # tasks.py from celery import shared_task from django.utils import timezone from datetime import timedelta shared_task def send_shoot_reminder(): tomorrow timezone.localdate() timedelta(days1) appointments Appointment.objects.filter( datetomorrow, statusconfirmed ).select_related(customer, photographer) for appt in appointments: customer_message f您好{appt.customer.name}您预约了明天{appt.get_slot_display()}的拍摄。 send_sms(appt.customer.phone, customer_message) photographer_message f{appt.photographer.name}明天{appt.get_slot_display()}有拍摄安排。 send_sms(appt.photographer.phone, photographer_message)这个任务里最坑的是重复发送问题。Celery Beat如果任务执行时间超过调度周期或者手动补跑同一个预约可能被通知两次。解决方案是加一张已通知记录表或者用Redis的SETNX做分布式锁。表方案更直观清晰在Appointment上增加一个reminder_sent字段发送前检查发送后置位。5.3 超时卡单的兜底方案业务流程上还有个常见问题状态长时间不流转。客户选完片之后一直没定精修张数或者修图师排期太满导致精修超时这种卡单如果没人盯就烂在系统里了。我加了一个周期扫描任务每天检查所有状态和停留时间超过阈值就提醒对应负责人。shared_task def check_overdue_orders(): today timezone.localdate() overdue_mapping { OrderStatus.CONFIRMED: 7, # 下单后7天未付定金 OrderStatus.DEPOSIT_PAID: 30, # 付定金后30天未拍摄 OrderStatus.SELECTING: 10, # 选片超10天 OrderStatus.RETOUCHING: 20, # 精修超20天 } for status, days in overdue_mapping.items(): orders Order.objects.filter( statusstatus, updated_at__date__ltetoday - timedelta(daysdays) ) for order in orders: notify_manager(order)小系统的定时任务不用搞得太复杂一个周期扫描函数把几种超时情况都查一遍比设计一堆消息队列状态机要实用得多。6. 权限、报表与运营后台让店长看得到数据6.1 四类角色的权限边界影楼系统的用户权限不需要做到很细的按钮级粒度分好四类角色就够了店长、前台、摄影师、客户。Django原生有Group和Permission体系但在这个项目里我用了更简单的方案在用户Profile上加一个role字段然后用装饰器或者中间件做视图层校验。原因在于影楼的管理后台本身使用人数就几十个细粒度的权限反而增加管理成本用角色字段更直观。权限分配逻辑大概是前台管客户、预约、订单创建摄影师只能看自己的拍摄任务和完成拍摄店长拥有一切权限包括报表查看、订单取消审批、套餐定价客户端的权限最低只允许查看自己的订单进度和拍摄档期。视图层用自定义装饰器做校验几行代码的事。from functools import wraps from django.http import JsonResponse from .models import UserProfile def role_required(*roles): def decorator(view_func): wraps(view_func) def wrapper(request, *args, **kwargs): profile UserProfile.objects.filter(userrequest.user).first() if not profile or profile.role not in roles: return JsonResponse({error: 无权限访问}, status403) return view_func(request, *args, **kwargs) return wrapper return decorator前端菜单根据role属性控制显示后端每个接口都校验双管齐下。6.2 Django Admin 秒变运营后台这个项目里Django Admin帮了大忙。店长要看的客户列表、订单列表、套餐管理、摄影师信息全部在Admin里就能操作。# admin.py admin.register(Order) class OrderAdmin(admin.ModelAdmin): list_display [id, customer, package, status, total_amount, paid_amount, created_at] list_filter [status, created_at] search_fields [customer__name, customer__phone] readonly_fields [id, created_at]list_filter按状态筛选订单search_fields搜索客户姓名或手机号readonly_fields防止误改关键字段。这三项配置下来这个后台对店长来说已经非常好用了省了一个前端管理页面的大开发量。6.3 基础报表用 ORM 聚合函数搞定店长要的数据其实不复杂这个月签了多少单、拍了多少组、哪个摄影师工作量最高、退款了多少。from django.db.models import Count, Sum # 本月签单总额 monthly_revenue Order.objects.filter( created_at__year2025, created_at__month3, status__in[OrderStatus.DEPOSIT_PAID, OrderStatus.SHOOT_DONE, OrderStatus.SELECTING, OrderStatus.RETOUCHING, OrderStatus.READY, OrderStatus.DONE] ).aggregate(totalSum(total_amount)) # 摄影师本月工作量排行 photographer_rank Appointment.objects.filter( date__year2025, date__month3, statusdone ).values(photographer__name).annotate( shoot_countCount(id) ).order_by(-shoot_count)这个数据量级用ORM聚合函数完全够。报表接口写好后前端用简单的Chart.js画两个柱状图一个看趋势一个看排行。整个过程没有引入大数据组件。7. 部署上线与实测经验7.1 生产环境最基础的三件事开发环境跑通和上线稳定运行是两码事。我在部署阶段做了三件事第一DEBUG改为False并配置ALLOWED_HOSTS第二用gunicorn启动Django应用第三用nginx做反向代理并托管静态文件。进程管理用supervisor避免手敲命令行一个疏忽服务挂了没人拉起来。supervisor配置一个简单的片段服务重启策略和启动命令都写清楚。[program:studio-api] command/www/wwwroot/studio/venv/bin/gunicorn -w 3 -b 127.0.0.1:8000 studio.wsgi:application directory/www/wwwroot/studio autostarttrue autorestarttrue userwwwnginx配置其实主要就两块静态文件直接让nginx处理所有API请求反代给gunicorn。配置不复杂但静态文件路径和FastDFS之类的都没必要影楼系统自己服务器磁盘就够用。7.2 实测中踩过的三个坑第一个坑就是这个系统在拍照时段的提醒验证第一次上线后客户凌晨收到短信。原因就是3.3节那个时区问题已经把修复方法写在前面了。这里要强调的是所有跟今天明天有关的逻辑都必须用timezone.localdate()不要图省事用datetime.date.today()因为后者拿到的是服务器本地时间而服务器很有可能就是UTC时区。第二个坑是数据库唯一约束导致的500错误。前台上在给客户约档期时非常容易短时间内连续点击提交两次第一次成功第二次被数据库的UniqueConstraint拦下来抛IntegrityError如果没有在视图层捕获用户端就直接白屏加服务器报错。解决方案是统一在创建预约的入口抓这个异常转为友好提示。第三个坑是Celery定时任务在DEBUG模式下重复执行。开发阶段没注意Celery Beat的调度和worker进程在本地同时跑浏览器一刷新就重复触发任务短信提醒发了两遍。最后在任务里加幂等标记字段解决。7.3 如果重来一次我会怎么设计这套系统从开发到上线基本完成了朋友的需求但复盘下来如果重来一次我会在一开始就做三件不同的事。第一先画业务状态图再写代码。订单状态当时是一边写代码一边加减如果先和店长把每个状态的前置条件和后置动作梳理清楚代码量能省三分之一。第二通知渠道从一开始就抽象成接口。短信、微信公众号模板消息、站内通知这三个渠道后面很可能都要接如果在一开始把所有通知调用统一封装成一个send_notification函数切换渠道就是改一行配置的事。第三预约模块和订单模块的边界要更清晰。预约是资源的安排订单是财务的流转两者在业务上是关联但不是一回事。写的时候把它们混在一起查后面做报表黑色。如果你正打算复现一个类似的项目我的建议是不要一上来就想着用微服务、消息队列那些大而全的架构。先把Python、Django、ORM、Admin、Celery这几样吃透把一个影楼的管理需求真正落地这个项目本身的含金量已经足够你熟悉一整条Web开发的流程了。就这套系统的体量来说三周时间从零到上线核心不是代码写得有多酷而是把业务流程问清楚了。程序帮影楼解决的撞档和跟丢问题本质上就是一套好的数据结构设计加上几个尽职的约束条件。数据模型立住了后面的代码就是顺着填肉的事。