Django模型修改及数据迁移实现解析


Posted in Python onAugust 01, 2019

Migrations

Django中对Model进行修改是件麻烦的事情,syncdb命令仅仅创建数据库里还没有的表,它并不对已存在的数据表进行同步修改,也不处理数据模型的删除。 如果你新增或修改数据模型里的字段,或是删除了一个数据模型,你需要手动在数据库里进行相应的修改或者使用South。Django 1.7中已经集成了South的代码,提供了3个新命令:

  • migrate: 用于执行迁移动作,具有syncdb的功能
  • makemigrations: 基于当前的model创建新的迁移策略文件
  • sqlmigrate: 显示迁移的SQL语句,具有sqlall的功能

使用起来很简单,对Model做了修改后,使用makemigrations记录修改:

$ python manage.py makemigrations
Migrations for 'books':
 0003_auto.py:
  - Alter field author on book

你的Model会被扫描, 然后与migrations文件夹中以前的版本作比较, 然后生成本次迁移文件。

有了新的migration文件,就可以使用migrate修改数据库模式:

$ 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:

$ python manage.py makemigrations your_app_label

也可以对数据库中的数据进行修改,首先建立一个空的migration文件:

python manage.py makemigrations --empty yourappname

文件的内容如下:

# -*- coding: utf-8 -*-
from django.db import models, migrations 
class Migration(migrations.Migration): 
  dependencies = [
    ('yourappname', '0001_initial'),
  ] 
  operations = [
  ]

如果想修改某个Model例如Person的数据,设置其name字段:

# -*- 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字段:

class 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语句。

CREATE 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语句来添加新列。

ALTER TABLE books_book ADD COLUMN num_pages integer;

添加 非NULL 字段

先创建 NULL 型的字段,然后将该字段的值填充为某个默认值,然后再将该字段改为 NOT NULL 型

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;

或者

ALTER TABLE <YourTable> ADD <NewColumn> <NewColumnType> NOT NULL DEFAULT <DefaultValue>;

添加ForeignKey或ManyToManyField

添加外键即是添加key_id的integer字段,添加多对多字段是创建一个新的数据表。

删除字段

比较简单,将表中的某列删掉即可

ALTER TABLE books_book DROP COLUMN num_pages;

使用sqlite3时,会有些麻烦,sqlite3不支持删除列操作,只有有限地 ALTER TABLE 支持。你可以使用它来在表的末尾增加一列,可更改表的名称。 如果需要对表结构做更复杂的改变,则必须重新建表。重建时可以先将已存在的数据放到一个临时表中,删除原表, 创建新表,然后将数据从临时表中复制回来。

如,假设有一个 t1 表,其中有 "a", "b", "c" 三列, 如果要删除列 c :

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;

删除多对多关联字段

删掉多对多关联的数据表即可

DROP TABLE books_book_authors;

删除模型

删除数据表即可

DROP TABLE books_book;

数据迁移

django 项目提供了一个导出的方法 python manage.py dumpdata, 不指定 appname 时默认为导出所有的app

python manage.py dumpdata myapp > 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"
  }
 }
]

数据导入:

python manage.py loaddata myapp.json

导出用户数据:

python manage.py dumpdata auth > auth.json

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python实现图片批量剪切示例
Mar 25 Python
python中使用xlrd、xlwt操作excel表格详解
Jan 29 Python
用Python解析XML的几种常见方法的介绍
Apr 09 Python
Python实现的爬虫功能代码
Jun 24 Python
Python3实战之爬虫抓取网易云音乐的热门评论
Oct 09 Python
python向字符串中添加元素的实例方法
Jun 28 Python
Python+Tensorflow+CNN实现车牌识别的示例代码
Oct 11 Python
Python3+selenium实现cookie免密登录的示例代码
Mar 18 Python
win10下python3.8的PIL库安装过程
Jun 08 Python
python Matplotlib基础--如何添加文本和标注
Jan 26 Python
Tensorflow与RNN、双向LSTM等的踩坑记录及解决
May 31 Python
OpenCV图像变换之傅里叶变换的一些应用
Jul 26 Python
Django 大文件下载实现过程解析
Aug 01 #Python
python爬虫刷访问量 2019 7月
Aug 01 #Python
用Cython加速Python到“起飞”(推荐)
Aug 01 #Python
Python爬取视频(其实是一篇福利)过程解析
Aug 01 #Python
flask框架jinja2模板与模板继承实例分析
Aug 01 #Python
Win10环境python3.7安装dlib模块趟过的坑
Aug 01 #Python
python爬虫解决验证码的思路及示例
Aug 01 #Python
You might like
PHP 程序员的调试技术小结
2009/11/15 PHP
php $_SERVER[&quot;REQUEST_URI&quot;]获取值的通用解决方法
2010/06/21 PHP
php下载excel无法打开的解决方法
2013/12/24 PHP
PHP把空格、换行符、中文逗号等替换成英文逗号的正则表达式
2014/05/04 PHP
php中用memcached实现页面防刷新功能
2014/08/19 PHP
完美实现wordpress禁止文章修订和自动保存的方法
2014/11/03 PHP
php实现点击可刷新验证码
2015/11/07 PHP
Laravel5.1 框架数据库操作DB运行原生SQL的方法分析
2020/01/07 PHP
eclipse导入jquery包后报错的解决方法
2014/02/17 Javascript
js对象的复制继承实例
2015/01/10 Javascript
Angular.JS判断复选框checkbox是否选中并实时显示
2016/11/30 Javascript
简单实现js拖拽效果
2017/07/25 Javascript
JavaScript数组push方法使用注意事项
2017/10/30 Javascript
详解Immutable及 React 中实践
2018/03/01 Javascript
vue2中使用less简易教程
2018/03/27 Javascript
利用JS动态生成隔行换色HTML表格的两种方法
2018/10/09 Javascript
Vuerouter的beforeEach与afterEach钩子函数的区别
2018/12/26 Javascript
前端Electron新手入门教程详解
2019/06/21 Javascript
jQuery实现判断滚动条滚动到document底部的方法分析
2019/08/27 jQuery
在JavaScript中实现链式调用的实现
2019/12/24 Javascript
JS实现滑动插件
2020/01/15 Javascript
[42:39]老党炸弹人试玩视频
2014/09/03 DOTA
python使用cookielib库示例分享
2014/03/03 Python
python使用Tesseract库识别验证
2018/03/21 Python
使用Python进行目录的对比方法
2018/11/01 Python
python 计算积分图和haar特征的实例代码
2019/11/20 Python
Django模板标签中url使用详解(url跳转到指定页面)
2020/03/19 Python
CSS3 实现的火焰动画
2020/12/07 HTML / CSS
爱奇艺VIP会员:大剧抢先看
2018/07/11 全球购物
竞选文艺委员演讲稿
2014/04/28 职场文书
大学本科生职业生涯规划书范文
2014/09/14 职场文书
会议通知范文
2015/04/15 职场文书
爱的教育观后感
2015/06/17 职场文书
Matlab如何实现矩阵复制扩充
2021/06/02 Python
MySQL非空约束(not null)案例讲解
2021/08/23 MySQL
教你nginx跳转配置的四种方式
2022/07/07 Servers