Django模型修改及数据迁移
Migrations
Django中对Model进行修改是件麻烦的事情,syncdb命令仅仅创建数据库里还没有的表,它并不对已存在的数据表进行同步修改,也不处理数据模型的删除。 如果你新增或修改数据模型里的字段,或是删除了一个数据模型,你需要手动在数据库里进行相应的修改或者使用South。Django 1.7中已经集成了South的代码,提供了3个新命令:
- migrate: 用于执行迁移动作,具有syncdb的功能
- makemigrations: 基于当前的model创建新的迁移策略文件
- sqlmigrate: 显示迁移的SQL语句,具有sqlall的功能
使用起来很简单,对Model做了修改后,使用makemigrations记录修改:
1 2 3 4 | $ python manage.py makemigrations Migrations for 'books' : 0003_auto .py: - Alter field author on book |
你的Model会被扫描, 然后与migrations文件夹中以前的版本作比较, 然后生成本次迁移文件。
有了新的migration文件,就可以使用migrate修改数据库模式:
1 2 3 4 5 6 7 8 9 10 11 | $ python manage.py migrate Operations to perform: Synchronize unmigrated apps: sessions, admin, messages, auth, staticfiles, contenttypes Apply all migrations: books Synchronizing apps without migrations: Creating tables... Installing custom SQL... Installing indexes... Installed 0 object (s) from 0 fixture(s) Running migrations: Applying books. 0003_auto ... OK |
也可以针对单独的app生成migration:
1 | $ python manage.py makemigrations your_app_label |
也可以对数据库中的数据进行修改,首先建立一个空的migration文件:
1 | python manage.py makemigrations - - empty yourappname |
文件的内容如下:
1 2 3 4 5 6 7 8 9 10 11 | # -*- coding: utf-8 -*- from django.db import models, migrations class Migration(migrations.Migration): dependencies = [ ( 'yourappname' , '0001_initial' ), ] operations = [ ] |
如果想修改某个Model例如Person的数据,设置其name字段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # -*- coding: utf-8 -*- from django.db import models, migrations def combine_names(apps, schema_editor): # We can't import the Person model directly as it may be a newer # version than this migration expects. We use the historical version. Person = apps.get_model( "yourappname" , "Person" ) for person in Person.objects. all (): person.name = "%s %s" % (person.first_name, person.last_name) person.save() class Migration(migrations.Migration): dependencies = [ ( 'yourappname' , '0001_initial' ), ] operations = [ migrations.RunPython(combine_names), ] |
最后运行 python manage.py migrate即可。这样Person中的所有对象的name字段都设置好了。
依据Model修改关系数据库是开发中的一个重要的问题,解决这个问题可以提升开发速度,不过要在生产环境中随便使用migrate操作数据库还是很危险的,有时候需要手动修改数据库。
手动修改数据库
当处理模型修改的时候:
- 如果模型包含一个未曾在数据库里建立的字段,Django会报出错信息。 当你第一次用Django的数据库API请求表中不存在的字段时会导致错误。
- Django不关心数据库表中是否存在未在模型中定义的列。
- Django不关心数据库中是否存在未被模型表示的table。
添加字段
-
在你的模型里添加字段。下例向Book模型添加num_pages字段:
123456789class
Book(models.Model):
title
=
models.CharField(max_length
=
100
)
authors
=
models.ManyToManyField(Author)
publisher
=
models.ForeignKey(Publisher)
publication_date
=
models.DateField()
*
*
num_pages
=
models.IntegerField(blank
=
True
, null
=
True
)
*
*
def
__unicode__(
self
):
return
self
.title
-
运行manage.py sqlall yourappname来测试模型新的CREATE TABLE语句。
1234567CREATE TABLE
"books_book"
(
"id"
serial NOT NULL PRIMARY KEY,
"title"
varchar(
100
) NOT NULL,
"publisher_id"
integer NOT NULL REFERENCES
"books_publisher"
(
"id"
),
"publication_date"
date NOT NULL,
"num_pages"
integer NULL
);
-
开启你的数据库的交互命令界面(比如,psql或者mysql,或者可以使用manage.py dbshell。 执行ALTER TABLE语句来添加新列。
1ALTER TABLE books_book ADD COLUMN num_pages integer;
添加 非NULL 字段
先创建 NULL 型的字段,然后将该字段的值填充为某个默认值,然后再将该字段改为 NOT NULL 型
1 2 3 4 5 | BEGIN; ALTER TABLE books_book ADD COLUMN num_pages integer; UPDATE books_book SET num_pages = 0 ; UPDATE books_book SET num_pages = NULL; COMMIT; |
或者
1 | ALTER TABLE <YourTable> ADD <NewColumn> <NewColumnType> NOT NULL DEFAULT <DefaultValue>; |
添加ForeignKey或ManyToManyField
添加外键即是添加key_id的integer字段,添加多对多字段是创建一个新的数据表。
删除字段
比较简单,将表中的某列删掉即可
1 | ALTER TABLE books_book DROP COLUMN num_pages; |
使用sqlite3时,会有些麻烦,sqlite3不支持删除列操作,只有有限地 ALTER TABLE 支持。你可以使用它来在表的末尾增加一列,可更改表的名称。 如果需要对表结构做更复杂的改变,则必须重新建表。重建时可以先将已存在的数据放到一个临时表中,删除原表, 创建新表,然后将数据从临时表中复制回来。
如,假设有一个 t1 表,其中有 "a", "b", "c" 三列, 如果要删除列 c :
1 2 3 4 5 6 7 8 | BEGIN TRANSACTION; CREATE TEMPORARY TABLE t1_backup(a,b); INSERT INTO t1_backup SELECT a,b FROM t1; DROP TABLE t1; CREATE TABLE t1(a,b); INSERT INTO t1 SELECT a,b FROM t1_backup; DROP TABLE t1_backup; COMMIT; |
删除多对多关联字段
删掉多对多关联的数据表即可
1 | DROP TABLE books_book_authors; |
删除模型
删除数据表即可
1 | DROP TABLE books_book; |
数据迁移
django 项目提供了一个导出的方法 python manage.py dumpdata, 不指定 appname 时默认为导出所有的app
1 | python manage.py dumpdata myapp > myapp.json |
导出的文件内容格式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | [ { "model" : "myapp.person" , "pk" : 1 , "fields" : { "first_name" : "John" , "last_name" : "Lennon" } }, { "model" : "myapp.person" , "pk" : 2 , "fields" : { "first_name" : "Paul" , "last_name" : "McCartney" } } ] |
数据导入:
1 | python manage.py loaddata myapp.json |
导出用户数据:
1 | python manage.py dumpdata auth > auth.json |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)