零基础入门python31:Django商城第一步------创建项目并跑通第一个请求

一、上一篇课后练习讲解
Python 基础阶段最后一个练习是把命令行任务管理器拆成多个模块。参考做法是把"读取输入、校验、业务处理、保存文件"分开,再用 python -m 从项目根目录启动。Django 项目也遵循同样的思路:配置、路由、业务应用各有职责。
上一篇课后练习完整答案
上一篇练习的要求已落实到下面完整文件;先运行项目测试,再用 curl 对照状态码和数据库持久化结果
答案要点:README 验收从空目录创建虚拟环境、迁移、测试和冒烟;记录版本、状态码和只读数据库等故障结果。
文件:README.md
完整参考答案文件
完整文件:README.md
text
# Flask Ledger 验收
python -m pip install -r requirements.txt
flask --app run.py db upgrade
python -m pytest -q
flask --app run.py run
完整参考答案文件
本篇对应的交付源码完整文件:flask-ledger/tests/test_app.py
python
def test_health(client):
assert client.get("/api/health").get_json() == {"status": "ok"}
def test_register_login_and_me(client):
response = client.post("/api/auth/register", json={"email": "A@example.com", "password": "password123"})
assert response.status_code == 201
assert client.post("/api/auth/login", json={"email": "a@example.com", "password": "password123"}).status_code == 200
assert client.get("/api/auth/me").get_json()["email"] == "a@example.com"
def test_ledger_flow(logged_client):
category = logged_client.post("/api/categories", json={"name": "餐饮"}).get_json()
created = logged_client.post("/api/transactions", json={
"kind": "expense", "amount": "28.50", "category_id": category["id"],
"happened_on": "2026-08-06", "note": "午饭",
})
assert created.status_code == 201
assert created.get_json()["amount"] == "28.50"
items = logged_client.get("/api/transactions").get_json()["items"]
assert len(items) == 1
stats = logged_client.get("/api/statistics/monthly?month=2026-08").get_json()
assert stats["expense"] == "28.50"
assert logged_client.delete(f"/api/transactions/{items[0]['id']}").status_code == 204
def test_users_cannot_share_categories(client):
client.post("/api/auth/register", json={"email": "first@example.com", "password": "password123"})
client.post("/api/auth/login", json={"email": "first@example.com", "password": "password123"})
category = client.post("/api/categories", json={"name": "工资"}).get_json()
client.post("/api/auth/logout")
client.post("/api/auth/register", json={"email": "second@example.com", "password": "password123"})
client.post("/api/auth/login", json={"email": "second@example.com", "password": "password123"})
response = client.post("/api/transactions", json={"kind": "income", "amount": "100", "category_id": category["id"]})
assert response.status_code == 404
验收命令:python -m pytest -q(Django 项目使用 python manage.py test)。预期测试通过;若失败先检查迁移、配置和事务回滚。
二、本篇完成什么
今天不急着写商品和订单。我们先完成一件能验证环境的事情:创建商城项目,启动开发服务器,访问 /api/health/,看到明确的 JSON 响应。
如果这一步没有跑通,后面所有模型、迁移和接口都会建立在错误环境上。
三、Django项目到底是什么
Django 项目由"配置容器"和"业务应用"组成:

config 不应该保存商品业务;shop 不应该偷偷读取命令行参数。这样拆开后,部署配置变化时不需要修改订单代码。
四、创建项目
在课程工作目录执行:
powershell
python -m venv .venv
.venv\\Scripts\\activate
pip install "Django>=5.0,<6" djangorestframework
django-admin startproject config django-shop
cd django-shop
python manage.py startapp shop
如果 django-admin 找不到,说明虚拟环境没有激活;如果 ModuleNotFoundError: django,说明依赖安装到了另一个 Python。
五、配置应用
1. config/settings.py
python
INSTALLED_APPS = [
# Django 自带用户、Session 和 Admin,商城会直接复用它们。
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'shop',
]
REST_FRAMEWORK = {
# 未登录用户可以浏览商品;需要购买时再在具体视图上收紧权限。
'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.AllowAny'],
}
INSTALLED_APPS 决定 Django 是否加载模型、迁移和 Admin。把 shop 写进去后,Django 才知道这个应用有数据库模型。
2. shop/views.py
python
from rest_framework.response import Response
from rest_framework.views import APIView
class HealthView(APIView):
"""给容器编排和人工检查使用的轻量健康检查。"""
authentication_classes = []
permission_classes = []
def get(self, request):
# 健康检查不查询业务表,避免数据库故障时把真实原因隐藏掉。
return Response({'status': 'ok', 'service': 'django-shop'})
这里没有把数据库查询放进健康检查,因为第一篇只验证 Web 进程是否能响应。后面会增加 /api/ready/,专门检查数据库是否可用;区分 liveness 和 readiness 是部署时很重要的设计。
3. shop/urls.py
python
from django.urls import path
from .views import HealthView
urlpatterns = [
path('health/', HealthView.as_view(), name='health'),
]
4. config/urls.py
python
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
# 总路由只负责把 /api/ 交给 shop,不实现业务细节。
path('api/', include('shop.urls')),
]
六、启动和查看结果
powershell
python manage.py check
python manage.py migrate
python manage.py runserver 127.0.0.1:8000
另开一个终端:
powershell
curl http://127.0.0.1:8000/api/health/
预期响应:
json
{"status":"ok","service":"django-shop"}
check 只检查配置,migrate 创建 Django 自带的用户和 Session 表,runserver 启动开发服务器。三条命令作用不同,不要把 runserver 当成迁移命令。
七、常见错误排查
| 现象 | 原因 | 处理 |
|---|---|---|
No module named django |
没有使用虚拟环境里的 Python | 重新激活 .venv 并运行 python -m pip install |
404 /api/health |
总路由没有 include shop.urls |
检查 config/urls.py 的 path('api/', ...) |
Apps aren't loaded yet |
在 Django 启动前导入模型 | 把模型导入放进视图或正确的 Django 入口 |
| 浏览器能访问、curl 失败 | 端口或地址不一致 | 确认 runserver 输出的监听地址 |
八、本篇验收
powershell
python manage.py check
python manage.py test
curl http://127.0.0.1:8000/api/health/
验收标准:system check 无问题;测试通过;健康检查返回 200 和 JSON;删除健康检查视图中的注释不会影响行为,但删除路由会导致 404。
九、课后练习
增加 /api/version/ 接口,返回 {'version': '0.1.0'},并写一个 Django 测试断言状态码、响应类型和字段值。下一篇会在这个项目上创建 Category 和 Product 模型,并解释迁移文件到底做了什么。
项目增量:商城目录和第一个请求
本篇目标不是记住 startproject 命令,而是理解 settings、urls、app 和模板各自负责什么。创建 shop app 后,把首页路由接到一个明确的 view,再用 Django test client 验收状态码。
python
from django.http import HttpResponse
def home(request):
return HttpResponse('shop is running')
验收 GET / 返回 200;若出现 404,依次检查项目 urls 是否 include shop.urls、路径是否带结尾斜杠以及应用是否加入 INSTALLED_APPS。课后练习增加 /health JSON 响应,下一篇创建商品模型。
十、把第一次请求做成可维护的接口
健康检查不应返回一段随意文本,推荐固定 JSON 契约并写测试:
python
from django.http import JsonResponse
def health(request):
return JsonResponse({"status": "ok", "service": "django-shop", "version": "0.1.0"})
python
from django.test import TestCase
class HealthTests(TestCase):
def test_health_contract(self):
response = self.client.get("/api/health/")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()["status"], "ok")
self.assertEqual(response["Content-Type"], "application/json")
manage.py check 检查配置,migrate 管理数据库结构,runserver 才是启动 HTTP 服务;三者分工不同。开发阶段先让 /api/health/ 稳定,后面每次增加模型、Serializer 或事务,都可以用它区分"进程坏了"与"业务依赖坏了"。本篇练习完成后,下一篇会在同一项目中加入 Category/Product,并用迁移而不是手工建表。
本篇结束:完整模块文件
下面是交付项目中真实存在的完整文件 django-shop/config/urls.py。它覆盖本篇新增逻辑以及前文已经完成的依赖代码;复制单个函数会丢失上下文,因此这里提供整份文件。
python
"""
URL configuration for config project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('shop.urls')),
]