通过数据库向Django模型添加字段的示例


Posted in Python onJuly 21, 2015

首先借用书本(book)的这个数据模型:

from django.db import models

class Publisher(models.Model):
  name = models.CharField(max_length=30)
  address = models.CharField(max_length=50)
  city = models.CharField(max_length=60)
  state_province = models.CharField(max_length=30)
  country = models.CharField(max_length=50)
  website = models.URLField()

  def __unicode__(self):
    return self.name

class Author(models.Model):
  first_name = models.CharField(max_length=30)
  last_name = models.CharField(max_length=40)
  email = models.EmailField()

  def __unicode__(self):
    return u'%s %s' % (self.first_name, self.last_name)

class Book(models.Model):
  title = models.CharField(max_length=100)
  authors = models.ManyToManyField(Author)
  publisher = models.ForeignKey(Publisher)
  publication_date = models.DateField()

  def __unicode__(self):
    return self.title


添加字段
当要向一个产品设置表(或者说是model)添加一个字段的时候,要使用的技巧是利用Django不关心表里是否包含model里所没有的列的特性。 策略就是现在数据库里加入字段,然后同步Django的模型以包含新字段。

然而 这里有一个鸡生蛋蛋生鸡的问题 ,由于要想了解新增列的SQL语句,你需要使用Django的 manage.py sqlall命令进行查看 ,而这又需要字段已经在模型里存在了。 (注意:你并 不是非得使用与Django相同的SQL语句创建新的字段,但是这样做确实是一个好主意 ,它能让一切都保持同步。)

这个鸡-蛋的问题的解决方法是在开发者环境里而不是发布环境里实现这个变化。 (你正使用的是测试/开发环境,对吧?)下面是具体的实施步骤。

首先,进入开发环境(也就是说,不是在发布环境里):

    在你的模型里添加字段。

    运行 manage.py sqlall [yourapp] 来测试模型新的 CREATE TABLE 语句。 注意为新字段的列定义。

    开启你的数据库的交互命令界面(比如, psql 或mysql , 或者可以使用 manage.py dbshell )。 执行 ALTER TABLE 语句来添加新列。

    使用Python的manage.py shell,通过导入模型和选中表单(例如, MyModel.objects.all()[:5] )来验证新的字段是否被正确的添加 ,如果一切顺利,所有的语句都不会报错。

然后在你的产品服务器上再实施一遍这些步骤。

    启动数据库的交互界面。

    执行在开发环境步骤中,第三步的ALTER TABLE语句。

    将新的字段加入到模型中。 如果你使用了某种版本控制工具,并且在第一步中,已经提交了你在开发环境上的修改,现在,可以在生产环境中更新你的代码了(例如,如果你使用Subversion,执行svn update。

    重新启动Web server,使修改生效。

让我们实践下,比如添加一个num_pages字段到第五章中Book模型。首先,我们会把开发环境中的模型改成如下形式:

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 books 来查看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
);

新加的字段被这样表示:

"num_pages" integer NULL

接下来,我们要在开发环境上运行数据库客户端,如果是PostgreSQL,运行 psql,,然后,我执行如下语句。

ALTER TABLE books_book ADD COLUMN num_pages integer;

添加 非NULL 字段

这里有个微妙之处值得一提。 在我们添加字段num_pages的时候,我们使用了 blank=True 和 null=True 选项。 这是因为在我们第一次创建它的时候,这个数据库字段会含有空值。

然而,想要添加不能含有空值的字段也是可以的。 要想实现这样的效果,你必须先创建 NULL 型的字段,然后将该字段的值填充为某个默认值,然后再将该字段改为 NOT NULL 型。 例如:

BEGIN;
ALTER TABLE books_book ADD COLUMN num_pages integer;
UPDATE books_book SET num_pages=0;
ALTER TABLE books_book ALTER COLUMN num_pages SET NOT NULL;
COMMIT;

如果你这样做,记得你不要在模型中添加 blank=True 和 null=True 选项。

执行ALTER TABLE之后,我们要验证一下修改结果是否正确。启动python并执行下面的代码:

>>> from mysite.books.models import Book
>>> Book.objects.all()[:5]

如果没有异常发生,我们将切换到生产服务器,然后在生产环境的数据库中执行命令ALTER TABLE 然后我们更新生产环境中的模型,最后重启web服务器。

Python 相关文章推荐
python中的reduce内建函数使用方法指南
Aug 31 Python
Python实现登录接口的示例代码
Jul 21 Python
Python合并同一个文件夹下所有PDF文件的方法
Mar 11 Python
Flask框架学习笔记之路由和反向路由详解【图文与实例】
Aug 12 Python
YUV转为jpg图像的实现
Dec 09 Python
python基于property()函数定义属性
Jan 22 Python
python剪切视频与合并视频的实现
Mar 03 Python
python对接ihuyi实现短信验证码发送
May 10 Python
详解python with 上下文管理器
Sep 02 Python
pytorch Dataset,DataLoader产生自定义的训练数据案例
Mar 03 Python
python 如何在 Matplotlib 中绘制垂直线
Apr 02 Python
Python中常见的反爬机制及其破解方法总结
Jun 10 Python
Django的数据模型访问多对多键值的方法
Jul 21 #Python
举例讲解Django中数据模型访问外键值的方法
Jul 21 #Python
编写自定义的Django模板加载器的简单示例
Jul 21 #Python
详解Python的Django框架中inclusion_tag的使用
Jul 21 #Python
剖析Django中模版标签的解析与参数传递
Jul 21 #Python
Python简单调用MySQL存储过程并获得返回值的方法
Jul 20 #Python
在Django的上下文中设置变量的方法
Jul 20 #Python
You might like
雄兵连:天使彦天使彦为爱折翼,彦和炙心同时念动的誓言!
2020/03/02 国漫
Google Voice 短信发送接口PHP开源版(2010.5更新)
2010/07/22 PHP
谈谈关于php的优点与缺点
2013/04/11 PHP
PHP @ at 记号的作用示例介绍
2014/10/10 PHP
Yii中CGridView关联表搜索排序方法实例详解
2014/12/03 PHP
php版银联支付接口开发简明教程
2016/10/14 PHP
详细解读php的命名空间(一)
2018/02/21 PHP
PHP排序算法之基数排序(Radix Sort)实例详解
2018/04/21 PHP
Yii框架常见缓存应用实例小结
2019/09/09 PHP
JavaScript Distilled 基础知识与函数
2010/04/07 Javascript
nodejs批量修改文件编码格式
2015/01/22 NodeJs
node.js操作mysql(增删改查)
2015/07/24 Javascript
JavaScript正则表达式的分组匹配详解
2016/02/13 Javascript
js拖拽的原型声明和用法总结
2016/04/04 Javascript
jQuery绑定事件on()与弹窗的简要概述
2016/04/27 Javascript
细说webpack源码之compile流程-rules参数处理技巧(1)
2017/12/26 Javascript
react配合antd组件实现的管理系统示例代码
2018/04/24 Javascript
d3.js实现自定义多y轴折线图的示例代码
2018/05/30 Javascript
Vue项目History模式404问题解决方法
2018/10/31 Javascript
Vue源码中要const _toStr = Object.prototype.toString的原因分析
2018/12/09 Javascript
在Vue项目中使用snapshot测试的具体使用
2019/04/16 Javascript
vue-cli history模式实现tomcat部署报404的解决方式
2019/09/06 Javascript
[39:21]LGD vs OG 2019国际邀请赛淘汰赛 胜者组 BO3 第二场 8.24
2019/09/10 DOTA
有关wxpython pyqt内存占用问题分析
2014/06/09 Python
python数据类型_元组、字典常用操作方法(介绍)
2017/05/30 Python
详解python列表(list)的使用技巧及高级操作
2019/08/15 Python
利用python实现PSO算法优化二元函数
2019/11/13 Python
Python基于wordcloud及jieba实现中国地图词云图
2020/06/09 Python
解决HTML5中滚动到底部的事件问题
2019/08/22 HTML / CSS
JD Sports芬兰:英国领先的运动鞋和运动服饰零售商
2018/11/16 全球购物
顶撞领导检讨书
2014/01/29 职场文书
四年级评语大全
2014/04/21 职场文书
党委干部批评与自我批评发言稿
2014/09/28 职场文书
用python批量解压带密码的压缩包
2021/05/31 Python
浅析Django接口版本控制
2021/06/26 Python
mybatis中sql语句CDATA标签的用法说明
2021/06/30 Java/Android