从0到1拆解一个Django电商商城:源码结构、核心模块与踩坑记录

10 0
糖可甜 发表于 2026-8-14 13:03:33 | 查看全部 阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
0到1拆解一个Django电商商城:源码结构、核心模块与踩坑记录
本文导读

最近帮朋友看了一个Django写的网上购物商城项目,前后端一个人搞定的那种,功能不算复杂但该有的都有——用户注册登录、商品分类搜索、购物车、订单、后台管理全齐了。这篇文章我把这个项目的源码拆开来讲,从目录结构到核心模块的代码,再到部署时踩的坑,尽量讲透。适合想用Django做Web项目、或者做毕设的同学参考。
一、项目概览:这个商城系统能干什么


img_0.jpg img_1.jpg img_2.jpg
先看功能模块,一个典型的B2C商城该有的功能基本都覆盖了:
ecommerce_arch.jpg
1 电商系统功能模块架构(前台、中台、后台三层结构)
模块
前台用户功能
后台管理功能

用户模块

注册、登录、个人信息修改、密码找回

用户列表、用户状态管理、权限分配

商品模块

分类浏览、关键词搜索、商品详情、规格选择

商品增删改查、分类管理、上下架

购物车

加入购物车、数量修改、删除、结算



订单模块

下单、订单列表、订单详情、取消订单

订单列表、发货、退款处理

内容模块

购物资讯浏览、通知公告查看

资讯发布、公告管理、轮播图配置
整体分前台和后台两部分,前台给普通用户用,后台给管理员用。前台用Django模板渲染,后台直接用Django Admin做了定制,省了很多事——这也是Django做项目快的原因之一,后台不用自己写。
二、技术栈选型:为什么用Django

Web项目,Python生态里主要三个选择:Django、Flask、FastAPI。这个项目选了Django,我觉得是对的,原因如下:
框架
特点
适合场景
这个项目为什么不选

Django

全栈框架,自带ORM、Admin、Auth、表单

中大型项目、内容管理、电商

—(就是选的这个)

Flask

轻量微框架,自由度高,需要自己拼组件

小型API、原型、微服务

电商功能多,自己拼组件太费时间

FastAPI

异步高性能,自动生成API文档

高并发API、前后端分离

这个项目是模板渲染,不需要异步
Django的"全家桶"特性对这种功能完整的项目特别友好——用户认证用django.contrib.auth,后台用django.contrib.admin,数据库用ORM,表单用forms,连CSRF防护、分页、缓存都自带了。一个人开发的话,Django能让你把精力集中在业务逻辑上,而不是重复造轮子。
三、整体架构:MVT模式与项目结构

Django用的是MVT(Model-View-Template)模式,和传统的MVC有点像但叫法不同:Model对应数据层,View对应业务逻辑层,Template对应表现层。URL路由负责把请求分发到对应的View。
img_4.jpg img_5.jpg img_6.jpg
2 D
项目的目录结构大概是这样:
shop/
├── manage.py              # 项目管理脚本
├── shop/                  # 项目配置目录
│   ├── settings.py        # 全局配置(数据库、中间件、静态文件等)
│   ├── urls.py            # 根路由
│   └── wsgi.py            # WSGI入口
├── apps/
│   ├── user/              # 用户模块
│   │   ├── models.py      # 用户模型(扩展Django User)
│   │   ├── views.py       # 注册、登录、个人中心
│   │   ├── forms.py       # 注册表单、登录表单
│   │   └── urls.py        # 用户模块路由
│   ├── goods/             # 商品模块
│   │   ├── models.py      # 分类、商品、规格
│   │   ├── views.py       # 列表、详情、搜索
│   │   └── admin.py       # 后台管理配置
│   ├── cart/              # 购物车模块(基于Session)
│   ├── order/             # 订单模块
│   └── content/           # 资讯、公告模块
├── templates/             # 模板目录
│   ├── base.html          # 基础模板(导航、页脚)
│   ├── user/              # 用户相关页面
│   ├── goods/             # 商品相关页面
│   └── ...
└── static/                # 静态文件(CSS、JS、图片)
按功能模块拆app是Django的最佳实践,每个app只负责一块业务,代码组织清晰,后期维护也方便。我见过不少新手把所有代码都写在一个app里,到后期views.py几千行,改一个功能要翻半天——别这么干。
四、核心模块源码精读

4.1 用户认证模块

用户模块是整个系统的基础。Django自带了User模型,但字段不够用(没有手机号、昵称、头像),所以需要扩展。常用的扩展方式是用AbstractUser:
# apps/user/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models

class UserProfile(AbstractUser):
    """扩展用户模型"""
    phone = models.CharField('手机号', max_length=11, blank=True)
    nickname = models.CharField('昵称', max_length=50, blank=True)
    avatar = models.ImageField('头像', upload_to='avatar/', default='avatar/default.png')
    address = models.CharField('收货地址', max_length=200, blank=True)

    class Meta:
        verbose_name = '用户'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.username
然后在settings.py里指定AUTH_USER_MODEL = "user.UserProfile",这样Django就会用你自定义的用户表。注意这个配置一定要在第一次migrate之前设置好,后期改的话会很麻烦,数据库要重建。
注册视图用Django的Form组件做数据校验,比自己写if判断优雅得多:
# apps/user/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import UserProfile

class RegisterForm(UserCreationForm):
    email = forms.EmailField(required=True, label='邮箱')
    phone = forms.CharField(max_length=11, label='手机号')

    class Meta:
        model = UserProfile
        fields = ('username', 'email', 'phone', 'password1', 'password2')

    def clean_phone(self):
        phone = self.cleaned_data['phone']
        if not phone.startswith('1') or len(phone) != 11:
            raise forms.ValidationError('请输入正确的手机号')
        return phone
4.2 商品管理模块

商品模块是电商的核心。数据模型设计上,分类和商品是一对多,商品和规格是一对多:
# apps/goods/models.py
from django.db import models

class Category(models.Model):
    name = models.CharField('分类名称', max_length=50)
    parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, verbose_name='父分类')
    sort = models.IntegerField('排序', default=0)

    class Meta:
        verbose_name = '商品分类'
        ordering = ['sort']

class Goods(models.Model):
    name = models.CharField('商品名称', max_length=100)
    category = models.ForeignKey(Category, on_delete=models.CASCADE, verbose_name='分类')
    price = models.DecimalField('价格', max_digits=10, decimal_places=2)
    stock = models.IntegerField('库存', default=0)
    description = models.TextField('商品描述', blank=True)
    image = models.ImageField('主图', upload_to='goods/')
    is_on_sale = models.BooleanField('是否上架', default=True)
    created_at = models.DateTimeField('创建时间', auto_now_add=True)

    class Meta:
        verbose_name = '商品'
        ordering = ['-created_at']
商品搜索用Django ORM的icontains做模糊查询,小项目够用了:
# apps/goods/views.py
from django.db.models import Q
from .models import Goods

def goods_search(request):
    keyword = request.GET.get('keyword', '')
    goods_list = Goods.objects.filter(
        Q(name__icontains=keyword) | Q(description__icontains=keyword),
        is_on_sale=True
    )
    return render(request, 'goods/list.html', {'goods_list': goods_list, 'keyword': keyword})
如果商品量大、搜索要求高,可以换Elasticsearch或者Whoosh,但毕设级别用icontains完全够。
4.3 购物车模块(基于Session)

购物车有两种实现方式:存数据库或者存Session。这个项目用的是Session,优点是用户不登录也能用,缺点是换设备就没了。对于小型商城,Session方案足够:
# apps/cart/views.py
from django.shortcuts import redirect
from goods.models import Goods

def add_to_cart(request, goods_id):
    """加入购物车"""
    goods = Goods.objects.get(id=goods_id)
    cart = request.session.get('cart', {})

    if str(goods_id) in cart:
        cart[str(goods_id)]['quantity'] += 1
    else:
        cart[str(goods_id)] = {
            'name': goods.name,
            'price': float(goods.price),
            'quantity': 1,
            'image': goods.image.url,
        }

    request.session['cart'] = cart
    return redirect('cart:detail')

def cart_detail(request):
    """购物车详情"""
    cart = request.session.get('cart', {})
    total = sum(item['price'] * item['quantity'] for item in cart.values())
    return render(request, 'cart/detail.html', {'cart': cart, 'total': total})
这里有个坑:Django默认Session存在数据库里,每次修改Session都会触发数据库写入。如果购物车操作频繁,可以把Session换成Redis缓存,性能会好很多。
4.4 订单模块与状态机

订单是电商最复杂的模块,核心是订单状态的流转。这个项目的订单状态比较简单:待付款→已付款→已发货→已完成,外加已取消。用一个状态字段控制:
# apps/order/models.py
from django.db import models
from user.models import UserProfile

class Order(models.Model):
    STATUS_CHOICES = (
        (0, '待付款'),
        (1, '已付款'),
        (2, '已发货'),
        (3, '已完成'),
        (4, '已取消'),
    )
    order_no = models.CharField('订单号', max_length=32, unique=True)
    user = models.ForeignKey(UserProfile, on_delete=models.CASCADE, verbose_name='用户')
    total_amount = models.DecimalField('总金额', max_digits=10, decimal_places=2)
    status = models.IntegerField('订单状态', choices=STATUS_CHOICES, default=0)
    address = models.CharField('收货地址', max_length=200)
    created_at = models.DateTimeField('创建时间', auto_now_add=True)

class OrderItem(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='items')
    goods_name = models.CharField('商品名称', max_length=100)
    price = models.DecimalField('单价', max_digits=10, decimal_places=2)
    quantity = models.IntegerField('数量')
订单号生成用时间戳+用户ID+随机数,保证唯一性:
import time
import random

def generate_order_no(user_id):
    return f"{time.strftime('%Y%m%d%H%M%S')}{user_id}{random.randint(1000, 9999)}"
顺便说下前端怎么处理:订单列表页根据status显示不同的操作按钮,待付款显示"去付款",已发货显示"确认收货",已完成显示"再次购买"。这个用模板的{% if %}判断就行,不用写复杂的JS。
五、数据库设计:核心表结构

整个系统的核心实体关系如下:
img_8.jpg img_9.jpg img_10.jpg
3 电商系统核心ER图(用户、订单、商品、分类)
主要表的设计要点:
表名
核心字段
设计说明

user_profile

username, phone, email, password

继承AbstractUser,扩展手机号和昵称

category

name, parent_id, sort

自关联实现多级分类

goods

name, category_id, price, stock, is_on_sale

价格用Decimal不用Float,避免精度问题

order

order_no, user_id, total_amount, status

订单号唯一索引,状态用choices约束

order_item

order_id, goods_name, price, quantity

冗余商品名称和价格,防止商品修改后订单数据变化
这里有个重要的设计原则:订单里的商品名称和价格要冗余存储,不能只存商品ID。因为商品的价格和名称可能会改,如果只存ID,以后查历史订单时显示的就是修改后的价格,就不对了。这个坑很多新手会踩。
六、部署与踩坑记录




项目开发完只是第一步,部署到服务器上能跑才是真的完。这个项目部署的时候踩了几个坑,给大家避避雷:
1:DEBUG=False后静态文件404

开发时DEBUG=True,Django会自动处理静态文件。上线时DEBUG=False,Django就不管静态文件了,需要用Nginx或者whitenoise来处理。解决方案是配置STATIC_ROOT,运行python manage.py collectstatic把静态文件收集到一个目录,然后让Nginx直接 serve 这个目录。
2:MySQL时区不对

MySQL做数据库时,Django连接MySQL默认时区可能和服务器不一致,导致时间字段差8小时。在settings.py的DATABASES配置里加OPTIONS:{'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", 'charset': 'utf8mb4'},同时确保USE_TZ=True,TIME_ZONE='Asia/Shanghai'。
3:Session购物车在生产环境丢失

uWSGI或Gunicorn多进程部署时,如果Session存在数据库里没问题,但如果存在缓存里,要确保所有进程连的是同一个缓存服务。另外Session的过期时间要设置合理,默认是两周,购物车数据存两周有点长,可以改成7天。
七、可扩展方向

这个项目是基础版,想做得更完善可以往这几个方向扩展:
1. 接入支付:支付宝沙箱或者微信支付,订单状态自动更新;
2. 商品规格:SKU模型,支持颜色、尺寸等多规格;
3. 优惠券/满减:营销活动模块,订单计算时叠加优惠;
4. 缓存优化:热门商品、分类列表用Redis缓存,减少数据库查询;
5. 异步任务:订单超时自动取消、邮件通知用Celery异步处理;
6. 前后端分离:后端写REST API(用Django REST Framework),前端用Vue或React重写。
八、常见问题FAQ

Q:Django做电商会不会性能不够?
A:中小规模完全够。Django的性能瓶颈通常在数据库查询,做好索引、加缓存、用select_related/prefetch_related优化查询,日PV几万到几十万没问题。真到了百万级,再考虑微服务拆分也不迟。
Q:购物车存在Session里,用户清了浏览器缓存就没了怎么办?
A:可以做双写——用户登录后把Session购物车同步到数据库,未登录时用Session。或者直接用数据库存购物车,要求用户必须登录才能加购,很多电商都是这么做的。
Q:Django Admin能直接当生产后台用吗?
A:内部管理用完全可以,Django Admin功能很强大,列表过滤、搜索、批量操作、表单校验都有。但如果是给商家用的多租户后台,就需要自己写了,Admin不适合多租户场景。
Q:这个项目做毕设够不够?
A:功能上完全够,但毕设要注意几点:一是要有需求分析和系统设计文档,不能只交代码;二是数据库设计要规范,画ER图;三是测试部分要写测试用例和测试结果;四是论文里要突出你的技术亮点,比如用了什么设计模式、做了什么优化。
九、总结与延伸学习路径

这个Django电商项目虽然不大,但覆盖了Web开发的核心知识点:MVT架构、ORM、表单验证、Session、用户认证、后台管理、数据库设计。把这个项目吃透,再做其他Web项目就触类旁通了。
如果想继续深入,可以按这个路径学习:
1. 先把Django官方文档过一遍,特别是ORM、Forms、Admin这几块,这是Django的精华;
2. 学Django REST Framework,把项目改造成前后端分离的API服务;
3. 学Redis和Celery,给项目加缓存和异步任务;
4. 学Docker和Nginx,掌握容器化部署和反向代理配置;
5. 最后可以研究一下微服务架构,把单体项目拆成多个服务。
做全栈开发,最重要的是动手。看十篇教程不如自己写一个项目,遇到问题查文档、搜Stack Overflow,踩过的坑都是你的经验。一个人搞定一个完整项目,那种成就感是看教程体会不到的。

—— 全栈开发的乐趣就在于,从数据库到前端页面,从代码到部署,每一层都能自己掌控。

有问题欢迎评论区交流,需要完整项目结构和配置文件模板可以关注后续更新~

img_3.jpg
img_7.jpg
img_11.jpg
img_12.jpg
img_13.jpg
img_14.jpg
img_15.jpg
img_16.jpg
img_17.jpg
回复 转播

使用道具 举报

回复

高级模式
B Color Image Link Quote Code Smilies |上传

本版积分规则

学研领航向全体高校师生打造的一站式综合交流与资源服务平台,集知识学习、经验分享、资源下载、互动问答、职场成长、兼职实践于一体,覆盖校园生活、专业学习、求职就业、兴趣发展等全场景需求。

快捷导航

小黑屋
Copyright © 2026 学研领航 版权所有 陕ICP备2025077879号-1
关灯 在本版发帖 返回顶部
快速回复 返回顶部 返回列表