当你的Django应用跑起来之后,更新数据库就成了个绕不开的事儿。这更新分两大块:一是更新数据库的结构,比如给表加个新字段;二是更新里面的数据,比如把用户的状态从“激活”改成“暂停”。Django提供了一套很趁手的命令和API来干这些活,用对了能省不少心,用错了也可能把数据搞乱。咱们就从最常用的说起。
更新数据库结构,主要靠Django的迁移系统。你把模型(models.py里的类)改好了,得让数据库知道这个变化。第一步是创建迁移文件。这个文件记录了模型当前状态和上次状态的差异,像是一份给数据库的“施工图纸”。在项目根目录下运行这个命令,Django会自动扫描所有app的模型变化。
python manage.py makemigrations
如果你想针对某个特定的app生成迁移,比如只更新`blog`这个应用,可以在后面加上应用名。
python manage.py makemigrations blog
有时候Django可能没检测到你所有的修改,或者你想手动检查一下,加上`--dry-run`参数可以预览将要生成的迁移,而不实际创建文件。
迁移文件生成在对应app的`migrations`文件夹里,是一个以数字开头的Python文件。你可以打开它看看,里面就是Django准备对数据库进行的操作列表,比如创建表、增加字段。确认无误后,就要真正动数据库了,用`migrate`命令。
python manage.py migrate
这个命令会按照迁移文件的依赖顺序,依次执行所有尚未应用的迁移。和`makemigrations`一样,你也可以只迁移某个特定的app。
python manage.py migrate blog
直接运行`migrate`感觉像黑盒操作?你可以先用`sqlmigrate`命令看看它到底要执行什么SQL语句。这对于深度排查问题或者好奇背后原理很有帮助。
python manage.py sqlmigrate blog 0004_auto_20240119
有时候项目复杂,迁移多了,容易忘记当前状态。`showmigrations`命令能列出一个清晰的清单,告诉你哪些迁移已经应用了(前面会打上`[X]`),哪些还在等待。
python manage.py showmigrations
万一新迁移出了问题,你想回退到上一个版本怎么办?`migrate`命令后面可以跟一个迁移名称,作为目标。通常你会回退到上一个迁移文件。
python manage.py migrate blog 0003_previous_migration
如果你想把一个app的数据库表完全清空,并移除所有迁移记录(小心!这通常只在开发初期使用),可以用`migrate`的`zero`作为目标。
python manage.py migrate blog zero
说完了改结构,再来看怎么改数据。在Django里,最基础的数据更新是通过模型对象进行的。你从数据库取出一个对象,修改它的属性,然后调用`save()`方法。这个操作会更新该对象对应的数据库行。
python
from blog.models import Post
post = Post.objects.get(id=1)
post.title = "全新的标题"
post.save() # 这会生成一个UPDATE语句
当你需要批量更新一批对象,并且把它们改成同一个值的时候,用`update()`方法更高效。它在数据库层面直接执行一个`UPDATE`语句,而不需要把每个对象都加载到Python内存里。这在处理大量数据时速度极快。
python
# 把所有状态为“草稿”的文章,都改成“已发布”状态
Post.objects.filter(status='draft').update(status='published')
不过`update()`方法有个限制:它不会触发模型的`save()`方法,也不会发送`pre_save`或`post_save`信号。如果你依赖这些信号来做一些额外工作(比如自动更新修改时间),就得注意了。
如果你要批量更新很多对象,但每个对象更新的值不一样,Django 2.2之后提供了`bulk_update()`方法。它比循环调用`save()`高效得多,因为它把多个更新打包到少量SQL查询里。
python
posts = list(Post.objects.filter(category='old'))
for post in posts:
post.category = 'new'
Post.objects.bulk_update(posts, ['category']) # 仅批量更新‘category’字段
除了这些直接的更新操作,还有一些维护和优化的命令。比如,你和同事的迁移文件可能冲突了,产生了合并迁移。你可以用`makemigrations --merge`来解决,它会创建一个新的合并迁移。
当你改了数据库的引擎或者做了一些Django迁移系统跟踪不到的外部操作,可能需要用`--fake`参数。这个命令标记迁移为已执行,但实际上不运行SQL。这是个高级操作,用错了会导致迁移状态和实际数据库结构不一致。
python manage.py migrate --fake blog 0004_added_field
最后,有两个重要的习惯能帮你避免大麻烦。第一,在执行任何迁移,尤其是生产环境迁移之前,先备份你的数据库。第二,把生成的迁移文件纳入版本控制系统(比如Git)。这样,团队里每个人的数据库结构都能保持同步。
更新数据库结构像是在给一座运行中的图书馆修改书架布局,而更新数据则像是更新书架上的书籍信息。Django的这套工具,从`makemigrations`绘制蓝图,到`migrate`执行施工,再到`update()`和`bulk_update()`批量修改数据,基本覆盖了日常需求。关键是要理解每个命令和方法的适用场景和潜在影响。先在测试环境多演练几次,形成一套自己的操作流程,等到上生产环境时,心里就有底了。
推荐文章
