简介:这是一套面向Python初学者与Web开发入门者的购物商城管理系统实战源码,聚焦角色权限分离、前后端交互与数据库事务处理等核心开发场景。资源共60个文件,含23个Python后端逻辑文件(如server.py、mysql_op.py)、17个UI界面文件(基于PyQt设计,覆盖登录、商品浏览、订单管理等模块)、17张系统截图及1份SQL建表脚本(mall.sql),总大小仅417KB,轻量易部署。已有2431人学习下载,适合用于课程设计、毕业项目或自学练手。读者可完整掌握用户双角色(商家/顾客)权限控制、SQLite/MySQL数据库增删改查操作、密码哈希加密与会话管理、商品交易事务处理,以及PyQt界面与后端数据联动的全流程实现,目录结构清晰划分shop/、customer/、ui/等模块,便于分层理解与二次开发。
1. 项目概述与核心价值
最近在整理硬盘,翻出来一个几年前自己写的“购物商城管理系统”源码包,当时是为了给一个朋友的小型电商项目做技术验证。这个项目虽然不是什么惊天动地的架构,但麻雀虽小五脏俱全,从商品展示、用户管理、购物车、订单处理到简单的后台数据统计都涵盖了。今天把它拿出来,结合我这些年踩过的坑和新的理解,重新梳理一遍,分享给想用Python从零搭建一个电商后台的朋友们。无论你是想学习全栈开发、准备课程设计,还是为一个小型创业项目做技术储备,这套源码和背后的设计思路都能提供一个扎实的起点。
这个系统本质上是一个典型的B/S架构Web应用。用户通过浏览器访问商城前端,进行浏览、下单等操作;管理员通过另一个入口登录后台,管理商品、处理订单。技术栈上,我选择了经典的Python Web框架Django,搭配MySQL数据库和简单的HTML/CSS/JS前端。选择Django不是因为它最“潮”,而是因为它“全”。对于管理系统这类业务逻辑清晰、需要快速开发且对安全性有基本要求的项目,Django自带的后台管理、ORM、用户认证、表单处理等组件,能让你省下大量重复造轮子的时间,把精力集中在业务逻辑本身。很多新手一上来就想用最“炫”的微服务、前后端分离,结果在环境配置和基础组件联调上就耗尽了热情。这个项目展示的是一种“务实”的开发路径:先用一个成熟的全栈框架把核心功能跑通,理解数据如何在视图、模板、数据库之间流转,之后再考虑技术升级和架构优化。
2. 系统架构与核心模块设计
2.1 整体技术栈选型与考量
当初选型时,我主要考虑了以下几个点:开发效率、学习曲线、社区生态和项目需求。Python的Django框架在这几点上表现均衡。它的MTV(Model-Template-View)模式清晰,自带的管理后台(admin)对于管理系统类项目简直是“开箱即用”的神器,能瞬间生成一个功能尚可的后台,让我们在项目初期就能专注于前台用户功能的开发。数据库方面,MySQL是经典选择,稳定、免费、资料多,Django的ORM对它的支持也非常完善。前端没有用复杂的框架,就是原生的HTML、Bootstrap CSS和一点jQuery,目的是让后端开发者也能快速上手,理解前后端交互的本质。当然,你现在完全可以用Vue或React重构前端,那会是另一个层面的优化。
注意:对于真正上线的项目,仅靠Django admin是不够的。它适合内部人员使用,但面对复杂的业务权限、定制化操作界面时,你需要基于它进行深度定制,或者完全自己开发一套后台。本源码中的后台管理界面就是基于Django admin进行了一定程度的美化和功能扩展的示例。
2.2 核心数据模型(Models)设计解析
数据模型是整个系统的基石,设计得好,后续开发事半功倍。这个商城系统主要包含以下几个核心模型:
用户模型(User):直接使用了Django内置的
AbstractUser模型进行扩展。这样做的好处是直接拥有了用户名、密码、邮箱、权限组等基础字段,并且集成了强大的认证系统。我额外添加了phone(手机号)、address(收货地址)等字段。这里有个细节:用户密码Django会默认进行哈希处理并存储,绝对不要在数据库中存储明文密码。商品模型(Product):这是核心中的核心。字段包括
name(名称)、description(描述)、price(价格)、stock(库存)、image(主图)、category(分类外键)等。其中,价格字段我使用了DecimalField,并指定了max_digits=10和decimal_places=2,这是处理金额的标准做法,能避免浮点数计算带来的精度问题。图片字段使用ImageField,需要配合Pillow库和文件存储设置(如MEDIA_ROOT)。商品分类模型(Category):一个简单的树状结构,包含
name和parent(自关联外键,指向父分类)。通过parent字段可以实现无限级分类。在视图里,我们需要递归或使用一些库(如django-mptt)来高效地处理和展示这种树形数据。购物车模型(Cart)及购物车项模型(CartItem):这里采用了分离设计。
Cart模型关联用户(user),一个用户对应一个购物车。CartItem模型关联购物车(cart)和商品(product),并记录购买数量(quantity)。这种设计比把商品和数量直接以JSON形式存在Cart模型里更规范,利于后续的库存校验、订单生成等操作。订单模型(Order)及订单项模型(OrderItem):这是购物流程的终点。
Order模型记录订单整体信息:下单用户(user)、总金额(total_amount)、收货地址(shipping_address)、订单状态(status,如“待支付”、“已发货”、“已完成”等)、创建时间。OrderItem则记录订单中的具体商品:关联订单(order)、商品快照(product_name,product_price,这里存储快照而非直接关联商品,是因为商品信息后续可能会变更)、购买数量(quantity)。存储商品快照是一个非常重要的设计,它保证了订单历史数据的不可变性,即使后来商品下架或价格变了,用户当时下单的记录依然准确。
2.3 后台管理(Admin)定制化实战
Django Admin默认界面比较简陋,但定制能力很强。在这个项目里,我做了几处关键定制:
- 列表页优化:为
Product模型的管理类重写了list_display,显示商品名、价格、库存和分类,并添加了list_filter(按分类过滤)和search_fields(按名称搜索),大大提升了管理效率。 - 字段分组与只读设置:在
Order模型的admin中,使用fieldsets将订单信息、收货信息、商品项分组显示。将订单总价、下单时间等字段设置为readonly_fields,防止误操作。 - 自定义Action:添加了批量操作,例如“批量标记为已发货”。这需要定义一个方法,并将其加入到
actions列表中。 - 关联对象的内联编辑:使用
TabularInline或StackedInline,可以在编辑订单的同时,直接编辑该订单下的所有OrderItem,非常方便。
这些定制并不复杂,但能极大改善后台使用的体验。代码中都有体现,你可以参考admin.py文件。
3. 核心业务逻辑与视图层实现
3.1 用户认证与会话管理
用户登录、注册、登出是基础。Django提供了django.contrib.auth模块,我们主要使用authenticate(),login(),logout()这几个函数。在视图(View)里,处理登录的大致流程是:接收POST请求中的用户名密码 -> 调用authenticate()验证 -> 验证成功则调用login(request, user)将用户信息存入会话(Session) -> 重定向到首页。
这里有个安全细节:Django的Session默认存储在数据库里,对于访问量不大的系统没问题。如果考虑性能,可以换成缓存(如Redis)或文件存储。另外,记得在设置中配置SESSION_COOKIE_AGE(会话过期时间)和SESSION_SAVE_EVERY_REQUEST(是否每次请求都保存会话)。
注册视图需要自己写,核心是处理表单验证(检查用户名是否已存在、密码强度、邮箱格式等),验证通过后使用User.objects.create_user()方法创建用户,这个方法会自动处理密码哈希。
3.2 商品展示与购物车功能详解
商品列表页通常是一个简单的查询所有商品或按分类过滤的视图。分页是必须的,Django提供了Paginator类,很容易实现。前端通过GET参数传递页码。
购物车功能是交互的核心。主要操作有“加入购物车”、“查看购物车”、“修改数量”、“删除商品”。
- 加入购物车:视图接收商品ID和数量。首先获取或创建当前用户的购物车(
Cart对象),然后查找或创建对应的CartItem。这里的关键是库存预检查:在增加CartItem数量前,必须检查商品当前库存是否充足。如果不足,应返回错误提示。 - 查看购物车:视图获取当前用户的购物车,并取出所有关联的
CartItem,连同商品信息、小计等一并传给模板渲染。计算总价时在Python中完成,避免在前端进行复杂的计算(安全性考虑)。 - 修改/删除购物车项:通常通过AJAX请求实现,以提升体验。后端视图接收
CartItem的ID和新的数量(或删除指令),执行更新或删除操作,并返回JSON格式的结果(如新的商品小计、购物车总价)。同样,修改数量时要进行库存校验。
购物车数据我选择存储在数据库,而不是Session中。因为数据库存储更持久(用户关闭浏览器再打开,购物车还在),也能更方便地关联用户和进行复杂查询。缺点是会增加数据库压力,但对于中小型商城完全可以接受。
3.3 订单创建与状态流转
从购物车到生成订单,是整个系统最复杂的业务流程之一,涉及事务、库存锁定和状态机。
订单创建视图:
- 获取数据:从请求中获取收货地址等信息,从数据库中取出当前用户的购物车及所有商品项。
- 预校验:再次逐一检查每个购物车项对应商品的库存是否足够。这是防止在“加入购物车”到“下单”这段时间内,库存被其他订单买走的必要措施。
- 开启数据库事务:使用
django.db.transaction.atomic()装饰器包裹整个订单创建逻辑。这是至关重要的一步,确保订单创建、库存扣减、购物车清空这几个操作要么全部成功,要么全部回滚,避免产生数据不一致(比如扣了库存却没生成订单)。 - 创建订单:计算总价,创建
Order对象并保存。 - 创建订单项并扣减库存:遍历购物车项,为每个商品创建
OrderItem(保存商品快照),并原子性地扣减对应Product的stock字段。F()表达式在这里很有用:Product.objects.filter(id=item.product.id, stock__gte=item.quantity).update(stock=F('stock') - item.quantity),这个操作在数据库层面完成,能有效防止并发下的超卖。 - 清空购物车:删除该用户的所有
CartItem。 - 提交事务:如果所有步骤成功,事务自动提交。
订单状态管理: 订单状态(如“待支付”、“已支付”、“已发货”、“已完成”、“已取消”)定义了订单的生命周期。我使用
CharField配合固定选择项(choices)来定义。状态变更通常由管理员在后台触发(如点击“发货”按钮),也可能由第三方支付回调触发(如“支付成功”)。 在改变状态时,尤其是向“已完成”或“已取消”转变时,可能需要触发其他操作,例如“已完成”后增加商品销量统计,“已取消”后恢复库存。这些逻辑可以写在模型的save()方法中,或者使用信号(django.db.models.signals),但更清晰的做法是放在视图或特定的服务函数里。
4. 前端交互与用户体验优化
4.1 基于Bootstrap的响应式界面搭建
虽然核心是后端,但一个看得过去的前端对用户体验至关重要。我直接使用了Bootstrap 4的CDN。它的栅格系统能轻松实现响应式布局,在手机和电脑上都有不错的显示效果。组件库也很丰富,导航栏(Navbar)、卡片(Card)、按钮(Button)、表单(Form)样式直接套用,再稍加自定义CSS,就能得到一个风格统一、简洁明了的界面。
关键点在于模板(Template)的组织。Django的模板继承机制很好用。我创建了一个base.html作为基础模板,里面定义了整个网站的HTML骨架、引入的CSS/JS文件、导航栏和页脚。其他页面(如首页、商品列表页、商品详情页)只需要{% extends "base.html" %},然后填充各自的内容块({% block content %})即可。这保证了样式和结构的一致性,也便于维护。
4.2 异步请求(AJAX)提升操作流畅度
为了不让每个操作都刷新整个页面,我在几个关键地方使用了jQuery的AJAX:
- 加入购物车:在商品详情页,点击“加入购物车”按钮,通过AJAX POST请求将商品ID和数量发送到后端。后端处理成功后,返回一个JSON响应,前端再动态更新页面上的购物车图标数量或弹出成功提示。这样用户体验非常流畅。
- 更新购物车数量:在购物车页面,每个商品数量旁边有“+”和“-”按钮。点击后,通过AJAX发送新的数量到后端,后端更新数据库并返回该商品的新小计和购物车新总价,前端局部更新页面上的这两个数字。这比提交整个表单再刷新页面好得多。
- 验证码或实时搜索:虽然这个简单系统里没做,但AJAX同样适用于发送短信验证码、商品搜索提示等场景。
使用AJAX时,后端视图需要区分请求是普通的页面访问还是AJAX调用。可以通过检查request.headers.get('X-Requested-With') == 'XMLHttpRequest'来判断,并返回HTML片段或JSON数据。
4.3 静态文件与媒体文件处理
Django中,静态文件(Static Files)指CSS、JavaScript、图片等开发人员放置的资源,而媒体文件(Media Files)指用户上传的内容,如商品图片、用户头像。
- 开发环境:在
settings.py中配置STATIC_URL和MEDIA_URL,在urls.py中添加静态文件服务路由(使用static()函数),这样就能通过类似/static/css/style.css和/media/product_images/xxx.jpg的URL访问。 - 生产环境:绝对不能让Django直接提供静态/媒体文件,性能极差且不安全。必须使用Web服务器(如Nginx)或云存储服务(如AWS S3、阿里云OSS)来托管这些文件。在设置中配置
STATIC_ROOT和MEDIA_ROOT,然后使用python manage.py collectstatic命令收集所有静态文件到指定目录,再由Nginx指向该目录。媒体文件的上传路径也要配置到Nginx能访问的位置。
在模板中,始终使用{% static 'path/to/file' %}和{{ object.image.url }}这样的模板标签来生成文件URL,这样无论在开发还是生产环境,路径都是正确的。
5. 安全加固与性能考量
5.1 常见Web安全漏洞防护
- SQL注入:得益于Django的ORM,只要你使用它的查询API(如
filter(),get()),而不是直接拼接SQL字符串,就基本免疫SQL注入。这是使用框架的一大好处。 - 跨站脚本(XSS):Django模板默认会自动转义变量(
{{ variable }}),这能有效防止大部分XSS。但如果你确信某些内容是安全的HTML并使用了|safe过滤器,或者在前端用JavaScript动态插入HTML时,就要格外小心,必须对用户输入进行清洗。 - 跨站请求伪造(CSRF):Django内置了CSRF中间件。在任何可能修改数据的POST表单中,务必使用
{% csrf_token %}标签。对于AJAX的POST请求,需要在请求头中携带CSRF Token。 - 用户认证与权限:除了使用
@login_required装饰器保护需要登录的视图,更细粒度的控制需要使用@permission_required装饰器或Django的权限系统(Groups和Permissions)。例如,后台管理视图应该只允许is_staff的用户访问。 - 文件上传:限制用户上传文件的类型(通过检查文件扩展名和MIME类型)和大小。永远不要将上传的文件直接放在Web服务器的根目录下,也不要信任用户上传的文件名,最好重命名(如使用UUID)后存储。对于图片,可以使用
Pillow库进行验证,确保它是有效的图片文件。
5.2 数据库查询优化实践
随着数据量增长,糟糕的查询会成为性能瓶颈。Django ORM很方便,但也容易写出低效查询。
- N+1查询问题:这是最常见的性能杀手。例如,在渲染订单列表时,如果循环中通过
order.user.username访问用户信息,会导致为每个订单都执行一次数据库查询来获取用户。解决方案是使用select_related(用于一对一或外键关系)或prefetch_related(用于多对多或反向外键关系)。例如:Order.objects.select_related('user').all(),会在一次查询中通过JOIN连表获取所有订单及其关联的用户信息。 - 只取所需字段:使用
only()或defer()来限制查询返回的字段。如果你只需要商品的名称和价格,就不要把描述、详情图等大字段也查出来。 - 合理使用索引:在数据库表中,为经常用于查询条件(
WHERE)、排序(ORDER BY)和连接(JOIN)的字段创建索引,能极大提升查询速度。例如,Product表的category_id和price字段很可能需要索引。这需要在数据库层面操作(Django的Meta.indexes选项或直接执行SQL)。 - 分页:列表数据一定要分页。Django的
Paginator配合LIMIT和OFFSET(或更优的keyset pagination)是标准做法。
5.3 部署上线前的关键配置
开发环境和生产环境配置差异巨大。以下是一些必须调整的设置:
- DEBUG模式:在
settings.py中,必须设置DEBUG = False。否则,详细的错误信息会暴露给用户,带来安全风险。 - 密钥(SECRET_KEY):必须从环境变量中读取,而不是硬编码在代码里。可以使用
os.environ.get('SECRET_KEY')。 - 数据库:生产环境使用更健壮的数据库配置,如设置连接池、调整超时时间。考虑使用PostgreSQL以获得更好的性能和功能。
- ALLOWED_HOSTS:必须设置为你的域名列表,例如
['www.yourstore.com', 'yourstore.com'],防止HTTP Host头攻击。 - 静态/媒体文件:如前所述,配置正确的
STATIC_ROOT和MEDIA_ROOT,并配置Web服务器(如Nginx)来提供这些文件。 - 日志记录:配置Django的LOGGING,将错误信息记录到文件或日志服务中,方便排查问题。
- 使用WSGI服务器:不要用Django自带的
runserver上线。使用Gunicorn或uWSGI作为应用服务器,配合Nginx作为反向代理和静态文件服务器。这是Python Web应用的标准部署方式。
6. 项目扩展与二次开发指南
6.1 引入第三方支付接口
国内常用的有支付宝、微信支付。集成步骤大致如下:
- 申请商户号:在支付平台开通商户功能,获取商户ID(
appid)、密钥(key)、回调地址等。 - 安装SDK:通常支付平台会提供Python SDK,或者有社区维护的库(如
python-alipay-sdk)。 - 创建支付订单:在用户确认订单后,调用支付SDK,传入订单号、金额、商品描述等信息,生成一个支付参数或支付链接。
- 前端跳转:将支付链接或参数传递给前端,引导用户跳转到支付平台的页面完成支付。
- 处理异步通知:支付成功后,支付平台会向你在第1步设置的回调地址发送一个POST请求(异步通知)。这是最关键的一步,你必须在这个视图里:
- 验证通知的签名,确保请求来自支付平台。
- 根据通知中的商户订单号,找到本地对应的订单。
- 检查订单金额与通知金额是否一致(防止篡改)。
- 将订单状态更新为“已支付”。
- 处理后续逻辑(如减少库存、发送邮件通知等)。
- 处理完成后,必须返回一个成功的响应(如
'success'字符串)给支付平台,否则支付平台会认为通知失败,反复重试。
- 提供同步返回页面:用户支付完成后,支付平台会跳转回你指定的页面。这个页面通常用于展示支付成功的结果,但不能依赖这个页面来更新订单状态,因为用户可能不点击返回。订单状态的更新必须依赖上述的异步通知。
6.2 增加全文搜索与推荐功能
当商品数量上千时,简单的数据库LIKE查询会变得低效。可以引入Elasticsearch或Whoosh这样的全文搜索引擎。
- 集成Elasticsearch:使用
django-elasticsearch-dsl这类库。你需要定义与Django模型对应的Elasticsearch索引文档类。在商品保存或更新时,通过Django的信号机制,自动将数据同步到Elasticsearch。 - 实现搜索视图:接收用户搜索关键词,构造Elasticsearch查询(支持分词、模糊匹配、权重设置等),返回搜索结果并高亮显示。
- 简单推荐:可以基于协同过滤或内容过滤实现。一个简单的实现是:在用户浏览或购买某个商品后,在商品详情页推荐“购买了此商品的人也购买了…”或“相似商品”。这可以通过分析订单数据(找出频繁一起购买的商品组合)或基于商品分类/标签的相似度来计算。
6.3 从单体架构向微服务演进的思考
当前的源码是一个标准的单体(Monolithic)应用。当业务变得非常复杂,团队规模扩大时,可能会考虑微服务化。但这绝不是第一步就该考虑的。微服务带来了服务拆分、独立部署、通信、数据一致性等复杂问题。
如果未来真要演进,可以从一些边界清晰的模块开始尝试拆分,比如:
- 用户服务:负责所有用户相关的注册、登录、个人信息管理。
- 商品服务:负责商品的CRUD、分类管理、库存查询。
- 订单服务:负责创建订单、状态管理、支付回调处理。
- 购物车服务:作为一个独立的、可水平扩展的服务。
服务之间通过定义良好的API(如RESTful或gRPC)进行通信。数据库也需要按服务进行拆分,每个服务拥有自己的数据库,避免直接共享。这会引入分布式事务的挑战,可能需要使用最终一致性方案(如通过消息队列异步处理)。这个演进过程需要仔细的领域驱动设计(DDD)和大量的基础设施工作,对于大部分中小型项目,一个良好设计的单体应用仍然是性价比最高的选择。
7. 源码导读与本地运行指南
7.1 项目结构深度解析
解压购物商城管理系统源码.zip后,你会看到一个标准的Django项目结构。这里挑几个关键文件/目录说明:
shopping_mall/ # 项目根目录 ├── manage.py # Django命令行工具入口 ├── requirements.txt # 项目依赖包列表 ├── db.sqlite3 # 开发用的SQLite数据库(可能包含测试数据) ├── mall/ # 主项目配置目录(Project) │ ├── __init__.py │ ├── settings.py # **核心配置文件**,数据库、应用、中间件等都在此设置 │ ├── urls.py # **项目级URL路由**,将请求分发给各个应用 │ └── wsgi.py # WSGI入口,用于生产环境部署 └── apps/ # 应用目录,按功能模块划分 ├── user/ # 用户管理应用 │ ├── models.py # 用户、用户资料等数据模型 │ ├── views.py # 登录、注册、个人中心等视图 │ ├── urls.py # 用户相关URL路由(如 /user/login/) │ └── ... ├── product/ # 商品管理应用 │ ├── models.py # 商品、分类模型 │ ├── admin.py # 商品后台管理定制 │ └── ... ├── cart/ # 购物车应用 ├── order/ # 订单应用 └── static/ # 静态文件(CSS, JS, 图片) └── templates/ # HTML模板文件,按应用分子目录这种按功能划分应用(App)的方式,让代码结构清晰,耦合度低。每个应用理论上可以独立复用。
7.2 从零开始的环境搭建与运行
假设你已经在电脑上安装了Python(3.7以上版本)和pip。
- 创建虚拟环境(强烈推荐):在项目根目录打开终端,运行
python -m venv venv。然后激活它:- Windows:
venv\Scripts\activate - macOS/Linux:
source venv/bin/activate
- Windows:
- 安装依赖:在激活的虚拟环境中,运行
pip install -r requirements.txt。这个文件里主要包含了Django,Pillow,mysqlclient(如果用MySQL)等。 - 配置数据库:
- 如果你使用源码包内自带的
db.sqlite3(轻量,无需安装),只需确保settings.py中的DATABASES配置指向它即可。 - 如果想用MySQL,需要先安装MySQL服务器并创建一个数据库(例如
mall_db)。然后修改settings.py中的DATABASES配置,填入你的数据库名、用户名、密码和主机信息。同时,将requirements.txt中的mysqlclient安装好。
- 如果你使用源码包内自带的
- 应用数据库迁移:Django用迁移(Migration)文件来管理数据库表结构的变化。运行以下命令来创建数据表:
python manage.py makemigrations # 检测模型变化,生成迁移文件 python manage.py migrate # 执行迁移,创建或更新数据库表 - 创建超级用户(用于登录后台):运行
python manage.py createsuperuser,按提示输入用户名、邮箱和密码。 - 收集静态文件:运行
python manage.py collectstatic,这会将所有应用的静态文件收集到STATIC_ROOT指定的目录(生产环境用,开发环境可跳过)。 - 运行开发服务器:运行
python manage.py runserver。终端会输出类似Starting development server at http://127.0.0.1:8000/的信息。 - 访问系统:
- 打开浏览器,访问
http://127.0.0.1:8000/进入商城前台。 - 访问
http://127.0.0.1:8000/admin/进入后台管理,用刚才创建的超级用户登录。
- 打开浏览器,访问
7.3 自定义配置与数据初始化
- 修改设置:所有配置都在
mall/settings.py。你可以修改TIME_ZONE为'Asia/Shanghai',LANGUAGE_CODE为'zh-hans'来使用中文界面和时区。 - 导入初始数据:如果你想快速拥有一些测试商品和分类,可以使用Django的Fixture功能。将准备好的JSON数据文件(如
initial_data.json)放在应用目录下的fixtures文件夹里,然后运行python manage.py loaddata initial_data。你也可以通过后台管理界面手动添加。 - 修改前端样式:所有的CSS和JS都在
static目录下,HTML模板在templates目录下。你可以直接修改这些文件来改变网站的外观和交互。
这个项目源码是一个完整的、可运行的学习样本。我建议你不要仅仅满足于运行起来,而是尝试去修改它:增加一个“商品收藏”功能、实现一个简单的优惠券系统、或者给订单添加物流跟踪字段。在动手修改和调试的过程中,你会对Django和Web开发有更深刻的理解。编程就像学游泳,看再多的教程,也不如自己跳进水里扑腾几下学得快。
本文还有配套的精品资源,点击获取