☰
告别写死数据:Django连接数据库从零到企业级落地
2026/10/4 10:30:57 网站建设 项目流程

上周帮一个刚转行的朋友调代码,他的项目里二十几个 Python 列表把所谓“系统数据”写得明明白白:用户名单、库存清单、订单状态、菜单权限……数据全写在代码文件里,页面跑起来很顺,演示效果也不错。可一说到“企业级项目”,他就开始犯嘀咕:数据要改怎么办?别人能连吗?领导让加个报表统计,难道还得继续往代码里堆?现在这个问题有了一个不算复杂的答案——把“写死数据”换成“连接真实数据库”。这件事在过去是后端工程师的必修课,如今随着 Django 这类 Web 框架把 ORM、迁移、连接配置全都封装好,文科生、产品经理转开发、非科班同事,跨过这道坎的门槛确实又低了一点。这篇内容,我会把整个过程拆成能直接上手照做的步骤,顺便把那些不写在文档里的坑也讲清楚。

1. 写死数据到底坑在哪:三个必须换库的现实理由

1.1 需求一变,写死数据就要“人肉翻代码”

写死数据本身并不可耻,我特别理解新手为什么喜欢它。刚接触 Web 开发时,核心目标是先把页面跑起来,把一个列表塞进模板里,稍微循环一下就能展示,学习曲线极低。这里不涉及数据库安装、连接配置、SQL 报错,所有代码看起来都“非常合理”。

但问题出现在需求开始变化的那一刻。假设你写了一个商品列表:

products = [ {"name": "移动电源", "price": 99, "stock": 50}, {"name": "蓝牙耳机", "price": 199, "stock": 30}, ]

你只是在页面上展示它,一次部署两三个月的内部工具,完全没问题。可一旦领导说“把移动电源改叫快充移动电源,顺便价格调成 89”,你得搜代码;如果这个列表被三四个文件引用,你改完其一,可能漏掉另一个模板里的过滤条件。更麻烦的是,过阵子你可能在里面加上“上下架状态”字段,于是每个写死数据的地方都要同步调整结构。“写死”最伤人的不是写,而是改,改的时候你不知道哪个角落还藏着一份旧副本。

数据库解决的是“数据与代码分离”的问题。数据进入表里,字段结构由模型统一管理,页面展示通过查询读取,改数据就是改一条记录的事,不用再翻着代码找“还有哪里写死了”。这一步在工程上叫解耦,听起来玄乎,实际做一次就懂。

1.2 多用户并发时,写死数据活不过第一轮演示

如果只有你一个人操作,写死列表还算体面。但企业级项目往往意味着多人同时使用,比如人事在录员工、财务在看报销、管理员在调权限。这个场景下,写死数据的两个底层弱点立刻暴露。

第一,重启即失。你以为把数据放在内存列表或代码文件里就算“系统里有数据”,可一旦服务重启,原有的修改全部归零。第二个更隐蔽也更致命:不同用户进程之间看到的不是同一份数据。Python 里的普通列表和字典只在当前运行进程的内存中生效,A 同事新增的记录,B 同事的页面刷新一百遍也看不到。有人会说“那我存在 JSON 文件里,数据库不就是个能读写的文件吗?”话是没错,但 JSON 文件不具备并发控制。两个用户同时写同一个文件,晚到的覆盖早到的,甚至文件损坏,这种问题在真实项目里碰上一次就够你折腾半天。

数据库天生就是处理这种并发访问的。它内部有事务、锁机制、隔离级别,你能同时读写同一张表,系统会帮你排队、加锁、保证一致性。你不需要理解实现细节,只需要知道“把数据交给数据库,远比自己在代码里维护一个字典可靠”。

1.3 “企业级”三个字,其实就藏在数据库的底层能力里

很多人一听到“企业级”头就大,觉得是审计报表、分布式微服务、大数据平台那一套。实际上,对绝大多数中小项目来说,“企业级”的含义非常朴素:数据不丢、权限可控、多人可用、出了事故能恢复。

这四点恰恰是数据库的看家本领。数据持久化解决了“不丢”;用户账号和权限系统解决“可控”;事务和锁解决“多人可用”;备份和恢复工具解决“事故恢复”。你只要把数据从代码里搬进数据库,这些能力就自动到手,不用自己重写一遍。换句话说,写死数据让你从零造了一个轮子,而数据库是成熟的现成轮子,你选哪个?

2. 数据库连接没你想得那么难:文科生版三步拆解

2.1 选型:SQLite 起步,MySQL 和 PostgreSQL 按需切换

很多新手一上来就纠结“我应该学 MySQL 还是 PostgreSQL”,这个选择其实可以往后放。在 Django 这类框架里,更换数据库多数时候只是改一行配置,你的代码几乎不用变。

数据库安装成本适合场景一句话评价
SQLite零安装,一个文件学习、单机、数据量小最适合迈出第一步
MySQL需要安装服务常见企业项目、团队协作资料最多,招聘需求大
PostgreSQL需要安装服务复杂查询、地理数据、JSON开源界的新宠,功能更全面

我个人给新手的建议是:先用 SQLite 把流程走通,目录下会生成一个 db.sqlite3 文件,你不需要启动任何服务就能完成“连接数据库—建表—读写”的整个闭环。等你有把握了,再在服务器上装一个 MySQL,把连接配置改过去,顺便体会一下“换库”其实没那么大工程。

有人会担心“我学了 SQLite 是不是浪费时间”,不会。SQL、模型、迁移这些核心知识完全通用。数据库真正的区别集中在高并发优化、存储引擎、权限模型这些层面,那是后话,你现在用不上。

2.2 连接核心只有三件事:连接、读写、关闭

不管用什么数据库,不管用什么语言连接,你做的永远是三件事:先建立连接,再执行读写,最后关闭连接。这和去银行办事一模一样:取号排队(建立连接),递上身份证和单据(验证账号权限),业务办完(执行增删改查),离柜(关闭连接)。你不需要懂银行内部的结算系统,同样也不需要一开始就把数据库原理吃透,先建立这个心智模型后面就顺了。

一个连接通常需要四个参数:地址(HOST)、端口(PORT)、账号(USER)、密码(PASSWORD),再加一个数据库名(NAME)。说白了就是你拿着“门牌号和钥匙”去开仓库门。装一个图形化管理工具,比如 DBeaver,或者处理 SQLite 文件时用 DB Browser for SQLite,你会更直观地看到连上了什么库、有哪些表、哪些字段。

有一点值得强调:很多人卡在“我明明用管理工具能连上数据库,怎么程序里连不上”。差距往往出在驱动(Driver)上。图形工具自带驱动,你的代码缺一个驱动库。可以把驱动理解成“翻译官”,负责把你的代码语句翻译成数据库能懂的协议。装好驱动再写连接,问题就解决一大半。

2.3 ORM 就是翻译官:先不碰 SQL 也能操作数据库

“连接数据库是不是必须精通 SQL?”这是我经常被问到的问题。答案很明确:不一定。Django 自带一套 ORM(对象关系映射),它做的事是把“表”变成“类”,把“行记录”变成“对象”,把增删改查变成普通方法调用。

打个比方,你不会直接对仓库管理员喊货架编号和物理学移货规则,你只需要说“把库存大于 0 的商品都拿来”。ORM 就是那个仓库管理员,你调用Product.objects.filter(stock__gt=0),它内部帮你翻译成 SQL,把结果返回成 Python 对象。这一层封装对文科生特别友好,因为你不用一开始就背诵SELECT、WHERE、JOIN的语法细节。

但我也要说一句实在话:ORM 不是让你永远不学 SQL。至少你得看懂数据模型里“表、字段、主键、外键”这些概念,最好能在调试时认出简单查询语句。大多数时候你不需要手写 SQL,可一旦遇到性能问题或复杂统计,SQL 知识就是你的救命稻草。

3. 手把手实操:给“写死数据”项目装上真实数据库

3.1 环境准备:虚拟环境、Django 和数据库驱动

实操之前,先建一个干净的环境。为什么要用虚拟环境?因为不同项目依赖的第三方包版本可能冲突,虚拟环境相当于为每个项目单独准备一个“包运行室”,互不干扰。

在终端依次执行:

python -m venv venv source venv/bin/activate # Windows 下使用 venv\Scripts\activate pip install django pip install pymysql # 如果计划连 MySQL,先装驱动

先说说pymysql。如果你之后要连 MySQL,Python 默认没有 MySQL 驱动,需要额外安装。Django 官方推荐的是mysqlclient,但它在 Windows 上编译安装偶尔会折腾人;pymysql安装更省心,性能对小项目足够。如果你想连 PostgreSQL,把驱动换成psycopg2-binary即可。

这里有一个容易踩的坑:安装完成后,如果用的是 PyMySQL,通常需要在项目的__init__.py文件里加一行pymysql.install_as_MySQLdb(),让它冒充 MySQLdb 接口,Django 才能正常工作。忘记这一行,启动服务时大概率会报No module named 'MySQLdb'。

3.2 配置连接:替换 settings.py 里的 DATABASES

Django 新建项目后,默认用的是 SQLite,配置长这样:

DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } }

如果切换到 MySQL,改成:

DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'erp_demo', # 数据库名,要提前在 MySQL 里建好 'USER': 'erp_user', # 业务账号,不建议用 root 'PASSWORD': 'StrongPass123!', 'HOST': '127.0.0.1', 'PORT': '3306', } }

参数里NAME是你要操作的数据库名,注意这个库必须事先存在。如果用 SQLite,框架会自动创建文件;但用 MySQL、PostgreSQL 时,框架不会替你创建数据库。你先用管理工具或命令建好空库,再运行项目,否则报错“Unknown database”。

连接配置本质上就是一张“路线图”。ENGINE告诉 Django 用哪套数据库方言,HOST和PORT告诉它去哪里找你安装的数据库服务,USER和PASSWORD是通行证。现在你可能会想“我没装 MySQL 怎么办”,那就先保留 SQLite 配置,把后面的模型和迁移流程走完,再回头换 MySQL 感受差异。

3.3 建表不靠手写 SQL:用模型和迁移生成数据表

数据要从代码里搬进数据库,第一步是在某个 app 的models.py里定义模型。比如建立一个商品表:

from django.db import models class Product(models.Model): name = models.CharField(max_length=100) price = models.DecimalField(max_digits=10, decimal_places=2) stock = models.IntegerField(default=0) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return self.name

这里的CharField、DecimalField分别对应数据库里的字符类型、小数类型,auto_now_add=True表示插入时自动记录创建时间。定义完模型,接下来执行两条命令:

python manage.py makemigrations python manage.py migrate

makemigrations负责对比模型和数据库的当前状态,生成一份变更“草稿”;migrate负责把草稿真正执行到数据库里。你不需要手动写CREATE TABLE语句,框架会根据模型翻译成对应的建表语句,这是 Django 对新手最友好的地方之一。

执行完migrate后,你可以打开管理工具看一眼,会发现多出了一张名为myapp_product的表,字段和你定义的模型一一对应。存储数据的“货架”就这样搭好了,下面要做的就是往货架上摆货。

3.4 视图数据源切换:从写死列表到 ORM 查询

先回忆一下最初的写死写法:

def product_list(request): products = [ {"name": "移动电源", "price": 99, "stock": 50}, {"name": "蓝牙耳机", "price": 199, "stock": 30}, ] return render(request, "shop/product_list.html", {"products": products})

换成数据库查询后:

from .models import Product def product_list(request): products = Product.objects.all() return render(request, "shop/product_list.html", {"products": products})

模板几乎不用大改,原来你遍历列表里的字典,现在遍历的是 Product 对象。在模板里访问product.name、product.price,变量名换一下就行:

{% for product in products %} <tr> <td>{{ product.name }}</td> <td>{{ product.price }}</td> <td>{{ product.stock }}</td> </tr> {% empty %} <tr><td colspan="3">暂无商品</td></tr> {% endfor %}

为了让页面真的有数据,你可以先往库里塞几条记录。不用刻意去写导入脚本,Django 自带 Admin 后台,只要创建一个管理员账号,就能登录后台可视化地增删改数据:

python manage.py createsuperuser

然后把Product模型注册到admin.py:

from django.contrib import admin from .models import Product admin.site.register(Product)

启动开发服务,登录/admin,添加几条商品记录,再刷新商品页面,发现数据已经实时展示出来了。这一步的意义值得停下来体会:现在你修改一条数据,页面立刻跟着变,不再需要改代码重新部署。所谓“从写死数据到连接真实数据库”,核心转折就发生在这一刻。

4. 接入数据库之后的坑与“企业级”习惯

4.1 新手上线最容易踩的六个错误

我只写实践里真实遇到的报错,每一条后面附解决思路,方便你当成速查表。

现象常见原因解决思路
启动后提示 “no such table”忘记执行迁移先python manage.py makemigrations再migrate,别跳过
中文存储乱码数据库或表字符集不是 utf8mb4建库时指定CHARACTER SET utf8mb4,连接参数也加上charset='utf8mb4'
报错No module named 'MySQLdb'装了 PyMySQL 但没激活在__init__.py里执行pymysql.install_as_MySQLdb()
报错Access denied for user账号权限或主机限制不对检查 MySQL 里user@host的授权范围,单独建业务号授权
页面很卡,后台日志出现 “too many connections”连接没关闭或连接池太小确认每次连接用完关闭;Django 里配置CONN_MAX_AGE做持连接复用
密码里有@或/等特殊字符导致连接串解析失败连接串没有编码用urllib.parse.quote_plus对密码编码后再拼连接参数

这六条里,“连接没关闭”是最隐蔽的。很多人以为代码里查完数据就自动释放了,其实如果创建连接后没有显式关闭,连接会一直占用数据库资源。小项目一天访问量低可能无所谓,一旦用户量上来,数据库连接数会迅速满掉,表现为整个系统突然变卡或直接拒绝服务。Django 默认在请求结束时关闭连接,但如果用了长连接配置,需要认真理解CONN_MAX_AGE的作用,别随便设一个很大的数就完事。

4.2 事务:让核心操作要么全成,要么全不干

连接上数据库以后,你手里多了一把“原子操作”的武器,叫事务。事务解决的是“半成功”问题,举一个经典场景:用户下单时,既要生成订单,又要扣减库存。如果订单插入成功,扣库存时发现余额不足,程序抛异常,那这条订单就是一笔“脏数据”,账对不上。

用 Django 的transaction.atomic()可以把几个操作包成一个整体,中间任何一步失败,整体回滚,数据库回到操作前的状态:

from django.db import transaction with transaction.atomic(): order = Order.objects.create(user=user, product=product, amount=1) product.stock -= 1 product.save()

我建议所有“涉及两条以上写操作”的地方都考虑包上事务。对文科生来说,你不用掌握数据库的各种隔离级别细节,只要记住一条原则:一组必须同时成功或同时失败的操作,放进同一个事务块里。这能帮你避开大量上线后的数据对不上问题。

4.3 最小权限和备份:没人催你但你最好自己先做

“企业级”项目还有一个容易被忽略的部分,是权限和备份。很多同学本地开发图省事,直接拿 root 账号连数据库,这套搬到团队环境就是事故隐患。想象一下,所有人共用高权限账号,有人不小心执行了一条删除语句,连备份都没有,哭都来不及。

我的建议是从第一天就养成两个习惯:第一,为每个应用单独创建数据库账号,只授权它需要的权限。以 MySQL 为例,业务账号只需要增删改查,不需要 DROP 和 GRANT,用最小权限跑业务。第二,定期备份,哪怕只是手动备份,也比不备份强。Django 项目可以定期执行:

python manage.py dumpdata > backup.json

MySQL 也可以用官方的mysqldump导出全部数据。备份最好落到定时任务里,每天一次,别把“应该有备份”当成“真的有备份”。我见过太多朋友在系统跑了一个月后才发现从来没备份过,那种心跳加速的感觉不好受。

4.4 从“能连上”到“用得好”:下一步补什么

当你完成标题里说的这件事——从写死数据到连接真实数据库——你已经比很多只敢写演示项目的人前进了一大步。接下来的学习方向也清晰了:一是补一点基础 SQL,尤其学会WHERE聚合查询,能和 ORM 对照着写;二是补一点索引知识,发现页面查询变慢时知道是缺索引,而不是盲目加机器;三是补一点设计规范,比如什么时候拆表、什么时候用外键、什么时候只存 ID。

这三条不需要你现在猛学,遇到实际问题时回来查就够了。真正的进步往往是在“能跑”之后,被业务逼着解决的难题堆出来的。你先把“连接真实数据库”这条路走通,后面的事就自然有了抓手。

最后分享一个我个人的实际感受:每次帮人从写死数据切到数据库,最难的从来不是技术,而是下决心重新组织自己的代码。数据一旦从代码里搬出来,你会发现自己对项目的理解会突然上一个大台阶——你会开始想字段类型、想表关系、想谁有权限改数据,而不是只盯着页面长什么样。这种思维方式的变化,比多会几个技术点更值得高兴。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询