Django模型修改及数据迁移实现解析
Migrations
Django中对Model进行修改是件麻烦的事情,syncdb命令仅仅创建数据库里还没有的表,它并不对已存在的数据表进行同步修改,也不处理数据模型的删除。如果你新增或修改数据模型里的字段,或是删除了一个数据模型,你需要手动在数据库里进行相应的修改或者使用South。Django1.7中已经集成了South的代码,提供了3个新命令:
- migrate:用于执行迁移动作,具有syncdb的功能
- makemigrations:基于当前的model创建新的迁移策略文件
- sqlmigrate:显示迁移的SQL语句,具有sqlall的功能
使用起来很简单,对Model做了修改后,使用makemigrations记录修改:
$pythonmanage.pymakemigrations Migrationsfor'books': 0003_auto.py: -Alterfieldauthoronbook
你的Model会被扫描,然后与migrations文件夹中以前的版本作比较,然后生成本次迁移文件。
有了新的migration文件,就可以使用migrate修改数据库模式:
$pythonmanage.pymigrate Operationstoperform: Synchronizeunmigratedapps:sessions,admin,messages,auth,staticfiles,contenttypes Applyallmigrations:books Synchronizingappswithoutmigrations: Creatingtables... InstallingcustomSQL... Installingindexes... Installed0object(s)from0fixture(s) Runningmigrations: Applyingbooks.0003_auto...OK
也可以针对单独的app生成migration:
$pythonmanage.pymakemigrationsyour_app_label
也可以对数据库中的数据进行修改,首先建立一个空的migration文件:
pythonmanage.pymakemigrations--emptyyourappname
文件的内容如下:
#-*-coding:utf-8-*-
fromdjango.dbimportmodels,migrations
classMigration(migrations.Migration):
dependencies=[
('yourappname','0001_initial'),
]
operations=[
]
如果想修改某个Model例如Person的数据,设置其name字段:
#-*-coding:utf-8-*-
fromdjango.dbimportmodels,migrations
defcombine_names(apps,schema_editor):
#Wecan'timportthePersonmodeldirectlyasitmaybeanewer
#versionthanthismigrationexpects.Weusethehistoricalversion.
Person=apps.get_model("yourappname","Person")
forpersoninPerson.objects.all():
person.name="%s%s"%(person.first_name,person.last_name)
person.save()
classMigration(migrations.Migration):
dependencies=[
('yourappname','0001_initial'),
]
operations=[
migrations.RunPython(combine_names),
]
最后运行pythonmanage.pymigrate即可。这样Person中的所有对象的name字段都设置好了。
依据Model修改关系数据库是开发中的一个重要的问题,解决这个问题可以提升开发速度,不过要在生产环境中随便使用migrate操作数据库还是很危险的,有时候需要手动修改数据库。
手动修改数据库
当处理模型修改的时候:
- 如果模型包含一个未曾在数据库里建立的字段,Django会报出错信息。当你第一次用Django的数据库API请求表中不存在的字段时会导致错误。
- Django不关心数据库表中是否存在未在模型中定义的列。
- Django不关心数据库中是否存在未被模型表示的table。
添加字段
在你的模型里添加字段。下例向Book模型添加num_pages字段:
classBook(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): returnself.title
运行manage.pysqlallyourappname来测试模型新的CREATETABLE语句。
CREATETABLE"books_book"(
"id"serialNOTNULLPRIMARYKEY,
"title"varchar(100)NOTNULL,
"publisher_id"integerNOTNULLREFERENCES"books_publisher"("id"),
"publication_date"dateNOTNULL,
"num_pages"integerNULL
);
开启你的数据库的交互命令界面(比如,psql或者mysql,或者可以使用manage.pydbshell。执行ALTERTABLE语句来添加新列。
ALTERTABLEbooks_bookADDCOLUMNnum_pagesinteger;
添加非NULL字段
先创建NULL型的字段,然后将该字段的值填充为某个默认值,然后再将该字段改为NOTNULL型
BEGIN; ALTERTABLEbooks_bookADDCOLUMNnum_pagesinteger; UPDATEbooks_bookSETnum_pages=0; UPDATEbooks_bookSETnum_pages=NULL; COMMIT;
或者
ALTERTABLEADD NOTNULLDEFAULT ;
添加ForeignKey或ManyToManyField
添加外键即是添加key_id的integer字段,添加多对多字段是创建一个新的数据表。
删除字段
比较简单,将表中的某列删掉即可
ALTERTABLEbooks_bookDROPCOLUMNnum_pages;
使用sqlite3时,会有些麻烦,sqlite3不支持删除列操作,只有有限地ALTERTABLE支持。你可以使用它来在表的末尾增加一列,可更改表的名称。如果需要对表结构做更复杂的改变,则必须重新建表。重建时可以先将已存在的数据放到一个临时表中,删除原表,创建新表,然后将数据从临时表中复制回来。
如,假设有一个t1表,其中有"a","b","c"三列,如果要删除列c:
BEGINTRANSACTION; CREATETEMPORARYTABLEt1_backup(a,b); INSERTINTOt1_backupSELECTa,bFROMt1; DROPTABLEt1; CREATETABLEt1(a,b); INSERTINTOt1SELECTa,bFROMt1_backup; DROPTABLEt1_backup; COMMIT;
删除多对多关联字段
删掉多对多关联的数据表即可
DROPTABLEbooks_book_authors;
删除模型
删除数据表即可
DROPTABLEbooks_book;
数据迁移
django项目提供了一个导出的方法pythonmanage.pydumpdata,不指定appname时默认为导出所有的app
pythonmanage.pydumpdatamyapp>myapp.json
导出的文件内容格式:
[
{
"model":"myapp.person",
"pk":1,
"fields":{
"first_name":"John",
"last_name":"Lennon"
}
},
{
"model":"myapp.person",
"pk":2,
"fields":{
"first_name":"Paul",
"last_name":"McCartney"
}
}
]
数据导入:
pythonmanage.pyloaddatamyapp.json
导出用户数据:
pythonmanage.pydumpdataauth>auth.json
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。