简介:这是一套基于Django框架开发的二手商品交易平台(mymall)完整源码,面向Python Web开发初学者与Django进阶实践者,解决从零构建电商类应用的核心需求,涵盖用户管理、商品发布、购物车、订单处理及支付宝支付集成等典型业务模块。资源共90个文件,压缩包大小10.15MB,包含37个Python文件(含models、views、forms、migrations等Django核心组件)、12个HTML模板页(如register.html、order.html等完整页面结构)、10个JavaScript脚本(支持前端交互与动态加载)、9个CSS样式文件(含base.css、commodity/目录下响应式布局),以及PNG/GIF图片、字体文件(OTF/WOFF等)和支付宝密钥配置(public_key、private_key、appid),体现前后端分离与生产级工程组织。已有339人学习下载,提供可直接运行的完整项目结构、清晰的Django App拆分(app、mymall、static等)、规范的迁移文件序列(0001_initial.py至0014_...)及requirements.txt依赖清单,是理解Django MVC设计、电商系统模块化实现与第三方支付对接的优质实战范例。
1. 为什么一个叫 mymall 的 Django 二手商城,比照着源码跑不起来?
你下载了一个标着“基于 Django 框架的 mymall 二手商城设计源码”的压缩包,解压后看到manage.py、requirements.txt、mymall/和apps/目录,心里一热:这不就是现成的 Django 电商项目?但python manage.py runserver后页面 500,pip install -r requirements.txt卡在mysqlclient编译失败,python manage.py migrate报no such table mymall_goods——问题不在代码写得对不对,而在于Django 项目不是“解压即用”的软件,它是一套需按环境契约重建的运行时结构。这个标题里的 mymall 不是品牌名,而是项目根命名空间;它不提供开箱即用的 SaaS 服务,而是面向 Python Web 开发者的一套可调试、可拆解、可本地复现的二手交易业务逻辑骨架。适合刚学完 Django ORM 和 Admin 机制、正想用真实业务场景(商品发布、用户收藏、订单状态流转)来验证知识闭环的中级学习者,也适合需要快速搭建内部二手物资流转平台的运维或行政人员——前提是愿意花 2 小时配好 Python 环境、数据库和静态资源路径。
2. 从源码结构反推 mymall 的核心模块与 Django 版本适配逻辑
2.1 先看目录树:识别出哪些是 Django 原生约定,哪些是 mymall 特有业务层
解压后的典型结构如下(已过滤.git、__pycache__等非必要项):
mymall/ ├── manage.py ├── requirements.txt ├── mymall/ # 项目配置包(Django 生成的 settings.py 所在) │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── apps/ # mymall 自定义应用目录(非 Django 默认,属常见工程组织法) │ ├── goods/ # 商品管理:模型、视图、模板 │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── models.py │ │ ├── views.py │ │ └── templates/goods/ │ ├── users/ # 用户中心:登录、注册、收货地址 │ ├── orders/ # 订单系统:创建、支付状态、物流跟踪 │ └── cart/ # 购物车:Session 或数据库存储 └── static/ # 静态资源:CSS/JS/图片(注意:Django 5 默认不自动 serve) ├── css/ ├── js/ └── uploads/ # 用户上传的商品图(需配置 MEDIA_ROOT)提示:
apps/下各子目录含apps.py文件且__init__.py中声明default_app_config,说明该项目使用了 Django 的 App 配置机制,而非简单将所有模型堆在models.py。这种结构利于后期拆分微服务或按业务线隔离开发。
2.2 requirements.txt 解析:锁定 Django 版本与关键依赖链
打开requirements.txt,常见内容如下(以实际高频组合为例):
Django==4.2.11 Pillow==10.2.0 django-crispy-forms==2.1 django-compressor==4.4 mysqlclient==2.2.4 django-redis==5.3.0关键点有三:
- Django 4.2.x 是 LTS 版本,意味着它支持到 2026 年 4 月,兼容 Python 3.8–3.12,但不兼容 Python 3.13(若你装了最新版 Python,请降级);
mysqlclient是 C 扩展,Linux/macOS 需先装mysql-devel或libmysqlclient-dev,Windows 用户建议改用pymysql(在settings.py中替换ENGINE并加pymysql.install_as_MySQLdb());django-crispy-forms表明前端表单用了 Bootstrap 渲染,模板中会出现{% load crispy_forms_tags %}和{% crispy form %}语法,若没装该包,页面会报Invalid template variable。
2.2.1 验证 Django 版本兼容性的最小命令
在虚拟环境中执行以下命令,确认版本无冲突:
python -m django --version # 输出应为 4.2.11(或你 requirements 中指定的版本) pip list | grep -i "django\|mysql" # 检查是否同时存在 django 和 mysqlclient,且无 django-allauth、django-rest-framework 等未声明的依赖若pip install -r requirements.txt失败,优先排查mysqlclient:
- Ubuntu/Debian:
sudo apt-get install python3-dev default-libmysqlclient-dev build-essential - CentOS/RHEL:
sudo yum install python3-devel mysql-devel gcc - macOS:
brew install mysql-client && export PATH="/opt/homebrew/opt/mysql-client/bin:$PATH"
注意:不要用
pip install mysql-python(已废弃),也不要试图用--force-reinstall强刷,Django 4.2 与mysqlclient<2.2存在JSONField兼容性问题。
2.3 settings.py 关键字段校验:为什么 runserver 总报错?
mymall/mymall/settings.py是整个项目的中枢。mymall 源码中必须显式配置的 4 个字段,直接决定能否启动:
| 字段名 | 必填值示例 | 作用说明 | 常见错误 |
|---|---|---|---|
INSTALLED_APPS | ['apps.goods', 'apps.users', 'django.contrib.admin', ...] | 告诉 Django 哪些 App 参与路由、模型注册、模板加载 | 漏掉'apps.goods'→No module named 'apps.goods' |
DATABASES | {'default': {'ENGINE': 'django.db.backends.mysql', 'NAME': 'mymall_db', ...}} | 数据库连接参数 | NAME库不存在 →OperationalError: database does not exist |
STATIC_ROOT | BASE_DIR / 'staticfiles' | collectstatic输出路径(生产环境必需) | 未设 →runserver可运行,但collectstatic报错 |
MEDIA_ROOT | BASE_DIR / 'media' | 用户上传文件存储根目录 | 未设或路径无写权限 → 上传商品图失败 |
2.3.1 快速修复runserver启动失败的三步检查法
检查
INSTALLED_APPS是否包含所有apps/下子目录:# mymall/mymall/settings.py INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'apps.goods', # ← 必须存在 'apps.users', 'apps.orders', 'apps.cart', 'crispy_forms', # ← 若 requirements 有 django-crispy-forms,则必须加 ]临时切换为 SQLite,绕过 MySQL 配置障碍:
# 替换 DATABASES 配置(仅用于本地调试) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } }此时
python manage.py migrate会自动生成db.sqlite3,无需手动建库。强制收集静态文件并启用开发服务器静态服务:
python manage.py collectstatic --noinput python manage.py runserver --nostatic # Django 4.2 默认不 serve static,加 --nostatic 会 fallback 到开发模式
3. 用 Django Admin 快速验证 mymall 业务模型是否就绪
3.1 注册模型到 Admin:让后台可操作是验证数据层的第一步
mymall 的apps/goods/models.py通常定义了Goods,Category,GoodsImage等模型。若python manage.py runserver后访问http://127.0.0.1:8000/admin/显示空白或报Not Found,说明模型未注册。需检查apps/goods/admin.py:
# apps/goods/admin.py from django.contrib import admin from .models import Goods, Category, GoodsImage @admin.register(Goods) class GoodsAdmin(admin.ModelAdmin): list_display = ('name', 'category', 'price', 'stock', 'is_on_sale') list_filter = ('category', 'is_on_sale') search_fields = ('name', 'desc') @admin.register(Category) class CategoryAdmin(admin.ModelAdmin): list_display = ('name', 'parent', 'level') list_filter = ('level',) # 注意:GoodsImage 通常用 InlineModelAdmin 嵌入 Goods 编辑页 class GoodsImageInline(admin.TabularInline): model = GoodsImage extra = 3 # 重新注册 Goods,加入内联 @admin.register(Goods) class GoodsAdmin(admin.ModelAdmin): inlines = [GoodsImageInline] # ... 其他配置保持不变提示:Django Admin 默认只显示
User和Group。只有在admin.py中用@admin.register()或admin.site.register()显式注册的模型,才会出现在后台菜单栏。mymall 源码若漏掉此步,后台就是空的——这不是 bug,是故意留的验证关卡。
3.2 创建超级用户并登录:获取后台入口钥匙
Django Admin 需认证用户才能访问。执行:
python manage.py createsuperuser # 按提示输入用户名、邮箱、密码(密码不回显)若报django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet,说明INSTALLED_APPS中某个 App 的apps.py初始化失败(如引用了未安装的第三方包)。此时回到 2.3 节检查INSTALLED_APPS顺序和依赖完整性。
3.2.1 登录后必做的三件事:确认 mymall 核心业务流可走通
- 添加一个商品分类:进入
Categories→Add category→ 输入手机数码,level=1,parent=None; - 添加一个商品:进入
Goods→Add goods→ 填写名称iPhone 12 128G、价格3200、库存5,在Category下拉选中刚建的手机数码; - 上传一张商品图:在
GoodsImage内联区域点击Add another GoodsImage,选择本地图片上传。
成功后,访问http://127.0.0.1:8000/(首页)应能看到该商品卡片;点击进入详情页,应展示图片和价格。若首页 404,说明mymall/urls.py未正确 includeapps/goods/urls.py。
3.3 urls.py 路由链路解析:从根 URL 到商品详情页的完整路径
Django 路由是层级嵌套的。mymall 的典型路由结构为:
# mymall/mymall/urls.py from django.contrib import admin from django.urls import path, include from django.conf import settings from django.conf.urls.static import static urlpatterns = [ path('admin/', admin.site.urls), path('', include('apps.goods.urls')), # ← 根路径交由 goods app 处理 path('users/', include('apps.users.urls')), path('orders/', include('apps.orders.urls')), ] if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)# apps/goods/urls.py from django.urls import path from . import views urlpatterns = [ path('', views.GoodsListView.as_view(), name='goods_list'), path('detail/<int:pk>/', views.GoodsDetailView.as_view(), name='goods_detail'), ]注意:
path('detail/<int:pk>/', ...)中的<int:pk>表示 URL 参数必须为整数,且变量名为pk(primary key)。若你在 Admin 中新建商品后 ID 是 1,那么详情页 URL 就是/detail/1/。若访问 404,请检查views.py中GoodsDetailView是否继承DetailView并设置了model = Goods。
4. 宝塔面板部署 mymall:绕过 Nginx 配置陷阱的 4 个硬核参数
4.1 宝塔新建 Python 项目前的环境预检
宝塔(v8.0+)支持 Django 一键部署,但 mymall 源码常因以下三点失败:
- Python 版本不匹配:宝塔默认 Python 管理器装的是 3.9,而 mymall
requirements.txt要求 3.10+; - 项目路径含中文或空格:宝塔解析路径时会截断,必须用纯英文路径如
/www/wwwroot/mymall-prod; - 未提前创建数据库:宝塔的 MySQL 管理中需手动新建库
mymall_db,字符集选utf8mb4,排序规则utf8mb4_unicode_ci。
4.1.1 在宝塔终端中执行的初始化命令(逐行复制)
# 进入项目目录(假设已上传至 /www/wwwroot/mymall-prod) cd /www/wwwroot/mymall-prod # 创建虚拟环境(用宝塔已安装的 Python 3.10) /usr/bin/python3.10 -m venv venv source venv/bin/activate # 升级 pip 并安装依赖(跳过 Pillow 编译,用预编译轮子) pip install --upgrade pip pip install -r requirements.txt --find-links https://download.pytorch.org/whl/torch_stable.html --no-cache-dir # 收集静态文件(关键!否则前端 CSS/JS 404) python manage.py collectstatic --noinput # 迁移数据库(此时 DB 已在宝塔 MySQL 中建好) python manage.py migrate提示:
--find-links参数指向 PyPI 镜像,可加速Pillow等大包安装;--no-cache-dir防止磁盘爆满。
4.2 宝塔站点设置中的 4 个必调参数
在宝塔「网站」→「添加站点」→「Python 项目」中,填写以下值(其他保持默认):
| 字段 | 推荐值 | 为什么必须这样设 |
|---|---|---|
| 项目路径 | /www/wwwroot/mymall-prod | 不能是子目录如/www/wwwroot/mymall-prod/mymall,Django 会找不到manage.py |
| 项目启动文件 | mymall/wsgi.py | WSGI 是生产环境标准接口,不是manage.py |
| 项目启动命令 | gunicorn mymall.wsgi:application -c gunicorn.conf.py | 宝塔默认用uwsgi,但 mymall 源码更常配gunicorn;若无gunicorn.conf.py,改用gunicorn mymall.wsgi:application --bind 127.0.0.1:8000 --workers 2 |
| 静态文件路径 | /www/wwwroot/mymall-prod/static/ | 对应settings.py中STATIC_ROOT,宝塔据此自动配置 Nginxlocation /static/ |
4.2.1 手动补全 gunicorn 配置(防进程崩溃)
若源码未提供gunicorn.conf.py,在项目根目录新建该文件:
# gunicorn.conf.py import multiprocessing bind = "127.0.0.1:8000" bind_mode = "tcp" workers = multiprocessing.cpu_count() * 2 + 1 worker_class = "sync" worker_connections = 1000 timeout = 30 keepalive = 2 max_requests = 1000 max_requests_jitter = 100 daemon = False pidfile = "/www/wwwroot/mymall-prod/gunicorn.pid" loglevel = "info" access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"' accesslog = "/www/wwwroot/mymall-prod/logs/access.log" errorlog = "/www/wwwroot/mymall-prod/logs/error.log"注意:
bind地址必须与宝塔「网站」→「反向代理」中设置的目标地址一致(如http://127.0.0.1:8000),否则 Nginx 无法转发请求。
4.3 反向代理配置:让域名直通 mymall,而非显示 502
在宝塔「网站」→「你的域名」→「反向代理」中,添加一条规则:
- 代理名称:mymall-backend
- 目标URL:
http://127.0.0.1:8000 - 发送域名:
$host - 额外参数:勾选「启用缓存」、「缓存时间 3600 秒」
保存后,宝塔会自动生成 Nginx 配置片段。此时检查/www/server/panel/vhost/nginx/your-domain.conf中是否包含:
location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }提示:若访问域名出现 502 Bad Gateway,90% 是
gunicorn进程未启动或端口被占用。执行ps aux | grep gunicorn查看进程,用kill -9 PID杀死旧进程后,再在宝塔「Python 项目」中点击「重启」。
5. 修复 mymall 前端图片不显示的 3 类根源及对应命令
5.1 MEDIA_URL 与 MEDIA_ROOT 不匹配:用户上传图永久 404
mymall 中商品图、用户头像等由用户上传,存储在MEDIA_ROOT,通过MEDIA_URL访问。若settings.py中设为:
MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media')则必须确保:
- Linux 系统中
/www/wwwroot/mymall-prod/media/目录存在且www用户有读写权限; - Nginx 配置中显式声明
location /media/(宝塔反向代理默认不处理/media/,需手动加)。
5.1.1 宝塔 Nginx 手动追加 media 静态路由
编辑站点配置文件/www/server/panel/vhost/nginx/your-domain.conf,在server { }块内插入:
location /media/ { alias /www/wwwroot/mymall-prod/media/; expires 30d; access_log off; log_not_found off; }然后重载 Nginx:nginx -s reload或在宝塔「网站」→「你的域名」→「配置文件」中点击「重载配置」。
5.2 模板中图片路径写死:硬编码导致跨环境失效
检查apps/goods/templates/goods/detail.html中图片引用方式:
❌ 错误写法(绝对路径,仅本地有效):
<img src="/static/uploads/iphone12.jpg">✅ 正确写法(用 Django 模板变量 +url过滤器):
{% load static %} <img src="{{ goods.main_image.url }}" alt="{{ goods.name }}"> <!-- 或 --> <img src="{{ goods.goodsimage_set.first.image.url }}" alt="商品图">提示:
main_image是Goods模型中定义的ImageField字段;goodsimage_set是外键反向查询管理器。若模板中直接写{{ goods.image }},Django 会输出相对路径如uploads/iphone12.jpg,需拼上{{ MEDIA_URL }}才能构成完整 URL。
5.3 浏览器控制台报 CORS 错误:跨域请求被拦截
当 mymall 前端调用/api/goods/接口返回 JSON,但图片仍不显示,检查浏览器开发者工具「Network」标签页:
- 若图片请求状态码为
200但预览为空 → 图片文件损坏或 MIME 类型错误; - 若状态码为
0或Failed to load resource→ 浏览器阻止了跨域请求(常见于前后端分离部署,但 mymall 是传统 Django 模板渲染,此情况极少)。
此时执行以下命令验证图片文件是否真实可读:
# 进入 media 目录,检查文件权限和内容 cd /www/wwwroot/mymall-prod/media/uploads/ ls -lh file iphone12.jpg # 应输出 "JPEG image data..." head -c 20 iphone12.jpg | hexdump -C # 前 20 字节应为 JPEG 签名 ff d8 ff若file命令报cannot open 'iphone12.jpg' (No such file or directory),说明 Django 未将上传文件写入MEDIA_ROOT,需检查settings.py中FILE_UPLOAD_HANDLERS是否被篡改,或views.py中request.FILES未正确保存。
注意:Django 默认
FILE_UPLOAD_HANDLERS是['django.core.files.uploadhandler.MemoryFileUploadHandler', 'django.core.files.uploadhandler.TemporaryFileUploadHandler'],无需修改。重点检查views.py中保存逻辑:# apps/goods/views.py def upload_goods_image(request): if request.method == 'POST': image = request.FILES.get('image') if image: # 必须用 model.save() 或 FileSystemStorage().save() GoodsImage.objects.create(goods=goods, image=image) # ← 正确 # ❌ 错误:open('/wrong/path.jpg', 'wb').write(image.read())
本文还有配套的精品资源,点击获取