零基础入门python44:Django商城从空目录启动与最终验收
2026/9/2 8:13:04 网站建设 项目流程

零基础入门python44:Django商城从空目录启动与最终验收

一、上一篇课后练习讲解

库存边界测试应覆盖库存为 0、购买数量为 0、数量超过库存和正常购买四种情况;每种情况都要断言状态码和数据库库存,不能只看响应文本。

上一篇课后练习完整答案

上一篇练习的要求已落实到下面完整文件;先运行项目测试,再用 curl 对照状态码和数据库持久化结果
答案要点:接口测试检查状态码、响应头和数据库快照;库存不足、重复下单、并发锁和事务异常都有明确断言。

文件:shop/tests.py

完整参考答案文件

完整文件:shop/tests.py

fromdjango.testimportTestCasefrom.modelsimportOrderclassStockTests(TestCase):deftest_insufficient_stock_rolls_back(self):response=self.client.post("/api/orders/",{"items":[]},content_type="application/json")self.assertEqual(response.status_code,409)self.assertEqual(Order.objects.count(),0)

完整参考答案文件

本篇对应的交付源码完整文件:django-shop/shop/tests.py

fromdjango.contrib.authimportget_user_modelfromrest_framework.testimportAPITestCasefrom.modelsimportCategory,Order,ProductclassShopApiTest(APITestCase):defsetUp(self):self.user=get_user_model().objects.create_user(username='alice',password='password123')category=Category.objects.create(name='图书',slug='books')self.product=Product.objects.create(category=category,name='Python入门',slug='python',price='59.00',stock=5)deftest_products_are_public(self):response=self.client.get('/api/products/')self.assertEqual(response.status_code,200)self.assertEqual(response.data[0]['name'],'Python入门')deftest_checkout_requires_login(self):response=self.client.post('/api/checkout/',{'items':[{'product_id':self.product.id,'quantity':1}]},format='json')self.assertEqual(response.status_code,403)deftest_session_cart_checks_stock(self):response=self.client.post('/api/cart/',{'product_id':self.product.id,'quantity':2},format='json')self.assertEqual(response.status_code,201)self.assertEqual(response.data[str(self.product.id)],2)response=self.client.post('/api/cart/',{'product_id':self.product.id,'quantity':9},format='json')self.assertEqual(response.status_code,400)deftest_checkout_creates_order_and_reduces_stock(self):self.client.force_authenticate(self.user)response=self.client.post('/api/checkout/',{'items':[{'product_id':self.product.id,'quantity':2}]},format='json')self.assertEqual(response.status_code,201)self.assertEqual(response.data['total_amount'],'118.00')self.product.refresh_from_db()self.assertEqual(self.product.stock,3)self.assertEqual(Order.objects.get().user,self.user)deftest_insufficient_stock_rolls_back_order(self):self.client.force_authenticate(self.user)response=self.client.post('/api/checkout/',{'items':[{'product_id':self.product.id,'quantity':9}]},format='json')self.assertEqual(response.status_code,400)self.assertEqual(Order.objects.count(),0)

验收命令:python -m pytest -q(Django 项目使用 python manage.py test)。预期测试通过;若失败先检查迁移、配置和事务回滚。

二、最终项目结构

django-shop/ ├─ manage.py ├─ config/ │ ├─ settings.py │ └─ urls.py └─ shop/ ├─ models.py ├─ serializers.py ├─ views.py ├─ services.py ├─ admin.py ├─ urls.py ├─ migrations/ └─ tests.py

三、从空目录运行

python-m venv.venv.venv\\Scripts\\activate pip install-r requirements.txt python manage.py migrate python manage.py createsuperuser python manage.py runserver

访问/admin/创建分类和商品,再用 API 完成浏览、加入购物车、登录结算和订单查询。生产环境使用 MySQL 时,必须先配置DATABASES、utf8mb4 和专用数据库账号,再执行完整迁移和测试。

四、毕业验收清单

  • 未登录可以浏览上架商品,但不能结算;
  • 用户只能查看自己的订单;
  • 库存不足不会创建半条订单;
  • 商品价格修改不影响历史订单快照;
  • Admin 可以运营商品,但不能绕过业务审计修改订单事实;
  • python manage.py test全部通过;
  • python manage.py check无问题。

Django 商城阶段至此形成独立可运行项目。下一篇进入 FastAPI 博客,从 ASGI、Pydantic 和依赖注入开始实现另一套后端架构。

五、毕业练习

为商城写一份 API README,列出认证方式、请求体、状态码和错误示例,并录制一次从创建商品到成功下单的终端演示。

项目增量:从空目录验收 Django 商城

python-m venv.venv.venv\\Scripts\\python.exe-m pip install-r requirements.txt.venv\\Scripts\\python.exe manage.py migrate.venv\\Scripts\\python.exe manage.py test-v 0.venv\\Scripts\\python.exe manage.py runserver

验收 Admin 商品维护、登录、购物车、下单、库存锁、DRF 商品列表和订单权限;保存测试输出与关键 curl 响应。数据库迁移文件、环境变量和 seed 数据必须能从空目录复现。

课后练习

把商城 README 改成新同学可执行的清单,包含初始化、测试、接口示例、失败场景和清理命令;下一阶段进入 FastAPI 博客项目。

五、上一篇练习讲解:从并发测试回到可复现命令

并发库存测试必须在 PostgreSQL 上跑,SQLite 只用于快速单元测试。README 应明确依赖:Python 3.11、Django 5、DRF、PostgreSQL 16,以及迁移顺序。不要把“本机已有 db.sqlite3”当作交付物,验收从空目录重新建库。

六、从空目录执行的完整清单

py-3.11-m venv.venv.venv\Scripts\Activate.ps1 python-m pip install--upgrade pip python-m pip install-r requirements.txtcopy.env.example.env python manage.py check python manage.py migrate--plan python manage.py migrate python manage.py createsuperuser python manage.py test-v 2 python manage.py runserver 127.0.0.1:8000

.env只保存数据库地址和密钥,不提交 Git;CI 使用临时 PostgreSQL 服务。若 PowerShell 禁止激活,可直接使用.venv\Scripts\python.exe -m pip ...,这比修改全局执行策略更安全。

七、毕业演示脚本

  1. Admin 创建分类和商品,设置库存 5。
  2. 注册普通用户并登录,调用商品列表确认只能看到is_active=True
  3. 把商品加入购物车,发送带幂等键的下单请求,得到 201;重复发送同 key 得到 200 且订单 id 相同。
  4. 再次下单超过库存,得到 409,查询数据库确认库存仍为 0、没有新增订单。
  5. 用户 B 查询用户 A 的订单,得到 404;staff 使用发货接口将 paid 订单改为 shipped。

终端记录应包含请求、状态码和关键响应字段,但要打码 token、cookie、密码。验收报告同时附python manage.py testpython manage.py check的原始输出。

八、项目分层复盘与常见故障

config负责 settings/urls,shop.models描述数据,Serializer 负责 JSON 边界,View 负责 HTTP,services.py负责事务和库存,tests 固定业务契约。出现 404 先看 URL 路由;出现 403 看认证和权限;出现 409 看库存/幂等状态;出现 500 先查看服务端 traceback,再定位迁移或序列化字段。

九、Django 阶段毕业练习

把 README 改成可打印的验收清单,包含初始化、迁移、测试、接口示例、失败场景和清理命令;为订单增加 CSV 导出(仅限 staff),并写权限测试。完成后进入 FastAPI 博客项目,继续沿用“完整代码 + 设计解释 + 运行结果 + 排错 + 练习”的格式。

Django 阶段的最终交付不是一个能打开 Admin 的空项目,而是一条可演示业务链:运营建商品,用户登录并加入购物车,订单快照保存价格,事务锁住库存,DRF 返回稳定 JSON,权限测试阻止越权。将这条链录成终端脚本,任何新环境都能重放,才算完成验收。

本篇结束:完整模块文件

下面是交付项目中真实存在的完整文件 django-shop/shop/tests.py。它覆盖本篇新增逻辑以及前文已经完成的依赖代码;复制单个函数会丢失上下文,因此这里提供整份文件。

fromdjango.contrib.authimportget_user_modelfromrest_framework.testimportAPITestCasefrom.modelsimportCategory,Order,ProductclassShopApiTest(APITestCase):defsetUp(self):self.user=get_user_model().objects.create_user(username='alice',password='password123')category=Category.objects.create(name='图书',slug='books')self.product=Product.objects.create(category=category,name='Python入门',slug='python',price='59.00',stock=5)deftest_products_are_public(self):response=self.client.get('/api/products/')self.assertEqual(response.status_code,200)self.assertEqual(response.data[0]['name'],'Python入门')deftest_checkout_requires_login(self):response=self.client.post('/api/checkout/',{'items':[{'product_id':self.product.id,'quantity':1}]},format='json')self.assertEqual(response.status_code,403)deftest_session_cart_checks_stock(self):response=self.client.post('/api/cart/',{'product_id':self.product.id,'quantity':2},format='json')self.assertEqual(response.status_code,201)self.assertEqual(response.data[str(self.product.id)],2)response=self.client.post('/api/cart/',{'product_id':self.product.id,'quantity':9},format='json')self.assertEqual(response.status_code,400)deftest_checkout_creates_order_and_reduces_stock(self):self.client.force_authenticate(self.user)response=self.client.post('/api/checkout/',{'items':[{'product_id':self.product.id,'quantity':2}]},format='json')self.assertEqual(response.status_code,201)self.assertEqual(response.data['total_amount'],'118.00')self.product.refresh_from_db()self.assertEqual(self.product.stock,3)self.assertEqual(Order.objects.get().user,self.user)deftest_insufficient_stock_rolls_back_order(self):self.client.force_authenticate(self.user)response=self.client.post('/api/checkout/',{'items':[{'product_id':self.product.id,'quantity':9}]},format='json')self.assertEqual(response.status_code,400)self.assertEqual(Order.objects.count(),0)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询