ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

美多商城Django工程化实践:从源码解析到生产部署

2026/9/12 22:52:45 拓冰建站 浏览量
美多商城Django工程化实践:从源码解析到生产部署 简介这是一套基于Django框架开发的电商类实战项目源码——美多商城面向Python后端初学者及Django进阶学习者旨在通过完整可运行的商城系统帮助开发者掌握用户认证、商品管理、订单流程、支付对接等核心Web开发能力。资源包共225个文件涵盖103个Python后端逻辑文件、43个HTML模板页、22个JavaScript交互脚本、24个JPG与19个PNG图片资源以及CSS样式、SQL数据库初始化脚本和配置文件等结构清晰模块划分合理便于分层理解MVT架构实践。压缩包仅1.7MB轻量易部署适合本地快速运行与代码研读。目前已有7064人学习下载读者可直接获取完整商城前后端协同实现方案包括用户中心、商品详情、购物车、订单结算等关键业务模块源码以及配套静态资源组织方式与基础部署说明是Django工程化学习的优质参考范例。1. 美多商城不是Demo是Django工程化落地的典型切口你下载到的美多商城.zip不是一份“Hello World”式教学代码而是一个覆盖用户注册登录、商品浏览、购物车、订单生成、支付回调、后台管理全链路的中型电商系统源码。它用 Django 3.2主流 LTS 版本构建数据库默认 PostgreSQL部分分支兼容 MySQL前端采用 Jinja2 模板直出 原生 JS 交互未强耦合 Vue/React —— 这意味着你能清晰看到 Django 的 MTV 模式如何在真实业务中分层users、verifications、oauth、goods、carts、orders等 App 各司其职settings分环境配置utils封装短信/支付宝/Redis 工具类。它适合两类人刚学完 Django 基础、卡在“不知道项目怎么组织”的中级学习者以及需要快速验证某模块如 JWT 登录流程、库存扣减事务、异步发短信实现逻辑的在职开发者。别把它当黑盒跑起来就完事——真正价值在于拆解它如何用django.contrib.auth扩展用户模型、用django-redis缓存商品分类、用celery redis异步处理订单超时关闭。接下来我们按真实开发节奏从环境准备到核心模块复现一节一节剥开这个 ZIP 包里的工程实践。2. 解压后第一件事识别项目结构与关键依赖版本拿到美多商城.zip解压后先不急着pip install而是打开根目录看三样东西requirements.txt、manage.py所在路径、以及settings模块位置。这是判断项目是否可运行的黄金三角。常见结构是meiduo_mall/为项目包含__init__.py其下有meiduo_mall/settings/多环境配置和多个功能 App如users/。注意不要直接cd meiduo_mall python manage.py runserver—— 多数版本的settings是模块路径而非文件需指定配置。比如python manage.py runserver --settingsmeiduo_mall.settings.dev。2.1 依赖解析为什么必须锁定 django3.2.23 而非最新版requirements.txt中通常包含Django3.2.23 django-redis5.2.0 celery5.2.7 djangorestframework3.14.0提示Django 4.x 的ASGI默认启用、path()路由语法变更、Field.choices类型校验更严格会直接导致meiduo_mall的urls.py和models.py报错。3.2.23 是最后一个支持 Python 3.6 且兼容该商城所有中间件的 LTS 版本。用pip install -r requirements.txt安装前先确认 Python 版本python --version # 必须 ≥3.6推荐 3.8 或 3.9 which python # 避免系统自带 Python 干扰若报ModuleNotFoundError: No module named django说明虚拟环境未激活python -m venv venv source venv/bin/activate # Linux/macOS # venv\Scripts\activate # Windows pip install --upgrade pip pip install -r requirements.txt2.2 数据库配置PostgreSQL 与 MySQL 的切换要点meiduo_mall/settings/dev.py中数据库配置类似DATABASES { default: { ENGINE: django.db.backends.postgresql, HOST: 127.0.0.1, PORT: 5432, NAME: meiduo, USER: meiduo, PASSWORD: meiduo123, } }若想改用 MySQL需做三处修改修改ENGINE为django.db.backends.mysql安装mysqlclient非pymysqlpip install mysqlclient在dev.py顶部添加import pymysql pymysql.install_as_MySQLdb() # 仅当使用 PyMySQL 时需要mysqlclient 不需此行注意MySQL 用户需提前建库并授权CREATE DATABASE meiduo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER meiduolocalhost IDENTIFIED BY meiduo123; GRANT ALL PRIVILEGES ON meiduo.* TO meiduolocalhost; FLUSH PRIVILEGES;2.3 Redis 与 Celery异步任务的启动链路meiduo_mall/settings/dev.py中CACHES { default: { BACKEND: django_redis.cache.RedisCache, LOCATION: redis://127.0.0.1:6379/1, OPTIONS: {CLIENT_CLASS: django_redis.client.DefaultClient}, } } CELERY_BROKER_URL redis://127.0.0.1:6379/2 CELERY_RESULT_BACKEND redis://127.0.0.1:6379/3启动顺序必须是redis-server确保 Redis 服务运行celery -A meiduo_mall worker -l info启动 Celery Workerpython manage.py runserver启动 Django若 Celery 报Connection refused检查 Redis 是否监听127.0.0.1:6379非::1redis-cli ping # 应返回 PONG netstat -tuln | grep 63793. 核心模块复现从用户注册到订单生成的四步闭环美多商城的价值不在界面美观而在它把电商高频场景的 Django 实现封装成可复用模式。我们以「手机号注册 → 短信验证码登录 → 加入购物车 → 提交订单」为主线还原关键代码逻辑。3.1 用户注册基于手机号的唯一性校验与密码加密users/views.py中RegisterView继承CreateAPIView但关键在users/serializers.py的UserSerializerclass UserSerializer(serializers.ModelSerializer): password2 serializers.CharField(write_onlyTrue) sms_code serializers.CharField(write_onlyTrue) class Meta: model User fields (id, username, mobile, password, password2, sms_code) extra_kwargs { password: {write_only: True}, username: {required: False} # 允许不填用户名用手机号替代 } def validate(self, attrs): # 1. 密码一致性校验 if attrs[password] ! attrs[password2]: raise serializers.ValidationError(两次输入的密码不一致) # 2. 短信验证码校验调用 utils/sms.py 的 check_sms_code if not check_sms_code(attrs[mobile], attrs[sms_code]): raise serializers.ValidationError(短信验证码错误) # 3. 手机号唯一性Django 自动触发 unique_together if User.objects.filter(mobileattrs[mobile]).exists(): raise serializers.ValidationError(手机号已注册) return attrs def create(self, validated_data): # 删除不需要存库的字段 del validated_data[password2] del validated_data[sms_code] # 创建用户并加密密码 user User.objects.create_user( usernamevalidated_data[mobile], mobilevalidated_data[mobile], passwordvalidated_data[password] ) return user逻辑说明create_user()调用 Django 内置方法自动对password字段执行make_password()加密比手动hashlib.pbkdf2_hmac()更安全。extra_kwargs中write_onlyTrue确保password2和sms_code不进入序列化输出。3.2 购物车Redis 存储与合并逻辑carts/views.py使用Redis而非数据库存购物车因为高并发读写需求。关键在merge_cart_cookie_to_redis函数def merge_cart_cookie_to_redis(request, user): 登录时合并 Cookie 购物车到 Redis cart_str request.COOKIES.get(cart) # JSON 字符串如 {1: {count: 2, selected: true}} if not cart_str: return cart_dict json.loads(cart_str) redis_conn get_redis_connection(carts) pl redis_conn.pipeline() # 商品ID为keycount为value存入 hash cart_hash {} for sku_id, item in cart_dict.items(): cart_hash[sku_id] item[count] if cart_hash: pl.hset(fcart_{user.id}, mappingcart_hash) # 选中状态存入 set selected_ids [sku_id for sku_id, item in cart_dict.items() if item[selected]] if selected_ids: pl.sadd(fselected_{user.id}, *selected_ids) pl.execute()参数说明get_redis_connection(carts)读取settings.CACHES[carts]配置hset存哈希表商品ID→数量sadd存集合选中商品ID列表。Pipeline 保证原子性避免并发时数据错乱。3.3 订单生成数据库事务与库存扣减的强一致性orders/views.py的CommitOrderView是核心transaction.atomic def post(self, request): user request.user # 1. 创建保存点 save_id transaction.savepoint() try: # 2. 创建订单主表 order OrderInfo.objects.create( order_iddatetime.now().strftime(%Y%m%d%H%M%S) (%09d % user.id), useruser, addressrequest.data[address], pay_methodrequest.data[pay_method], statusOrderInfo.ORDER_STATUS_ENUM[UNPAID] if request.data[pay_method] ALIPAY else OrderInfo.ORDER_STATUS_ENUM[UNSEND] ) # 3. 遍历购物车创建订单商品表并扣减库存 cart_redis get_redis_connection(carts) cart_hash cart_redis.hgetall(fcart_{user.id}) selected_ids cart_redis.smembers(fselected_{user.id}) for sku_id in selected_ids: sku GoodsSKU.objects.select_for_update().get(idsku_id) # 加行锁 count int(cart_hash[sku_id]) if sku.stock count: raise serializers.ValidationError(f商品 {sku.name} 库存不足) sku.stock - count sku.sales count sku.save() # 4. 创建订单商品 OrderGoods.objects.create( orderorder, skusku, countcount, pricesku.price ) # 5. 清空购物车 cart_redis.hdel(fcart_{user.id}, *selected_ids) cart_redis.srem(fselected_{user.id}, *selected_ids) transaction.savepoint_commit(save_id) return Response({order_id: order.order_id}) except Exception as e: transaction.savepoint_rollback(save_id) raise e关键点select_for_update()对GoodsSKU行加锁防止超卖transaction.atomic确保整个流程要么全部成功要么回滚savepoint提供细粒度回滚能力比全局事务更灵活。4. 宝塔部署实战Nginx Gunicorn Supervisor 三件套配置本地跑通不等于生产可用。美多商城在宝塔面板部署需绕过三个坑静态文件收集、Gunicorn 进程管理、HTTPS 重定向。4.1 静态文件收集collectstatic的路径陷阱Django 默认将STATIC_ROOT设为/var/www/meiduo_mall/static/但宝塔站点根目录通常是/www/wwwroot/meiduo/。执行前先修改settings/prod.pySTATIC_ROOT os.path.join(BASE_DIR, staticfiles) # 改为相对路径 STATIC_URL /static/然后在项目根目录执行python manage.py collectstatic --noinput这会在项目目录下生成staticfiles/文件夹内含admin/、css/、js/等。宝塔站点设置中“网站目录”指向/www/wwwroot/meiduo/而“静态文件”需额外映射/static/到/www/wwwroot/meiduo/staticfiles/—— 否则 admin 界面样式丢失。4.2 Gunicorn 启动脚本进程守护与内存优化创建/www/wwwroot/meiduo/gunicorn.conf.pyimport multiprocessing bind 127.0.0.1:8000 bind_ssl None workers multiprocessing.cpu_count() * 2 1 worker_class sync worker_connections 1000 max_requests 1000 max_requests_jitter 100 timeout 30 keepalive 5 preload True daemon False raw_env [ DJANGO_SETTINGS_MODULEmeiduo_mall.settings.prod, PYTHONPATH/www/wwwroot/meiduo ]启动命令gunicorn -c /www/wwwroot/meiduo/gunicorn.conf.py meiduo_mall.wsgi:application参数说明workers按 CPU 核数动态计算preloadTrue预加载代码避免 fork 后重复导入raw_env注入 Django 环境变量否则manage.py无法识别 settings。4.3 Supervisor 进程管理自动重启与日志轮转宝塔的“软件商店”安装 Supervisor 后新建配置/etc/supervisor/conf.d/meiduo.conf[program:meiduo] command/www/wwwroot/meiduo/venv/bin/gunicorn -c /www/wwwroot/meiduo/gunicorn.conf.py meiduo_mall.wsgi:application directory/www/wwwroot/meiduo userwww autostarttrue autorestarttrue redirect_stderrtrue stdout_logfile/www/wwwroot/meiduo/logs/gunicorn.log stdout_logfile_maxbytes10MB stdout_logfile_backups10生效命令supervisorctl reread supervisorctl update supervisorctl start meiduo注意userwww必须与宝塔网站运行用户一致否则无权读取静态文件stdout_logfile路径需提前mkdir -p /www/wwwroot/meiduo/logs。5. Django Admin 美化与数据迁移调试技巧美多商城的admin.py已做基础定制但生产环境常需进一步优化。重点解决两个高频问题中文界面乱码、迁移失败回滚。5.1 Admin 中文支持Locale 与时间格式统一meiduo_mall/settings/base.py中确保LANGUAGE_CODE zh-hans TIME_ZONE Asia/Shanghai USE_I18N True USE_L10N True USE_TZ False # 注意美多商城用本地时间设为 False若 admin 界面仍显示英文在INSTALLED_APPS中确认django.contrib.admin在django.contrib.messages之前且MIDDLEWARE包含django.middleware.locale.LocaleMiddleware位置在SessionMiddleware之后、CommonMiddleware之前。5.2 迁移调试makemigrations冲突与showmigrations排查当多人协作修改模型后执行python manage.py makemigrations可能报You are trying to add a non-nullable field xxx to xxx without a default此时不能简单加default而应先python manage.py showmigrations查看哪些 migration 未应用若新 migration 依赖旧 migration用--fake-initialpython manage.py migrate --fake-initial对新增字段先设nullTrue运行migrate再用dbshell手动更新数据最后alter_field去nullTrue5.3 查询优化select_related与prefetch_related的选择表goods/views.py中商品列表页常连表查询# 错误N1 查询 skus GoodsSKU.objects.filter(category_idcategory_id) # 正确select_related 用于 ForeignKey一对一/外键 skus GoodsSKU.objects.select_related(type, goods).filter(category_idcategory_id) # 正确prefetch_related 用于 ManyToManyField 或反向外键 skus GoodsSKU.objects.prefetch_related(specs__spec_value).filter(category_idcategory_id)验证方法开启 Django SQL 日志在settings/dev.py中添加LOGGING { version: 1, disable_existing_loggers: False, handlers: {console: {level: DEBUG, class: logging.StreamHandler}}, loggers: {django.db.backends: {handlers: [console], level: DEBUG}} }观察终端输出的 SQL 语句确认是否从 10 条SELECT降到 1 条JOIN。本文还有配套的精品资源点击获取