视图函数应仅负责HTTP协议转换,业务逻辑须收口至Service层:输入结构化(如Pydantic模型)、Service类无状态、方法名动词开头,确保业务规则唯一落地。

因为视图函数会迅速变成“瑞士军刀”——既要处理请求解析、权限校验、业务流转、API调用、邮件发送,又要拼接模板、构造响应,最后连单元测试都写不下去。
视图函数里塞太多逻辑,request对象就成万能胶了
你可能会在 def order_view(request): 里顺手加一段 requests.post() 调第三方支付、再 send_mail() 发通知、顺手 cache.set() 清个库存缓存。问题不是它“不能跑”,而是:
- 同一段发邮件逻辑,在视图、管理命令、信号里各写一遍,改错一处,订单状态就对不上
-
request被当成全局上下文传进各种辅助函数,导致函数无法脱离 Django 环境单独测试 - 调试时发现
order_view执行慢,但根本分不清是数据库查得慢、还是邮件网关卡了、还是模板渲染拖了后腿
models.py 也不行,那 views.py 就是唯一出口?
不是出口,是闸口。Django 视图的本职是「协议转换」:把 HTTP 请求转成 Python 数据,再把 Python 数据转成 HTTP 响应。它不该承担“创建订单”这个业务动作的全部语义。真实场景中:
- 创建订单要校验库存、扣减、生成流水、发短信、更新用户积分——这些都不是 HTTP 协议关心的事
- 同一个“创建订单”动作,可能来自 Web 表单、后台管理页、celery 定时补单、甚至外部 webhook 回调
- 如果所有入口都直连
Order.objects.create(),那库存校验漏写一次,数据就脏了
那逻辑该放哪儿?别造轮子,用 Service 层收口
不是新建一个叫 services/ 的目录然后随便扔代码,而是明确三条线:
立即学习“Python免费学习笔记(深入)”;
- 输入必须结构化:
OrderCreateInput(Pydantic 模型),不接受裸dict或**kwargs - Service 类无状态:
__init__只接收可 mock 的依赖,如api_client=None、cache=None - 方法名动词开头:
create_order()、cancel_order(),不叫handle_order_flow() - 所有旧调用点必须替换:视图里删掉
order.save(),改成order_service.create_order(input_data)
最常被忽略的一点:Service 不是“多写一层”,而是“让业务规则有唯一落地位置”。哪怕现在只有你一个人开发,只要模型超过 3 个、下周就要加第二个开发者,services/ 目录就得在第一天就建好,并且第一个业务函数就从那里开始写。


















