通过数据库向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 相关文章推荐
详解Django框架中用户的登录和退出的实现
Jul 23 Python
Python制作刷网页流量工具
Apr 23 Python
Python+Turtle动态绘制一棵树实例分享
Jan 16 Python
django限制匿名用户访问及重定向的方法实例
Feb 07 Python
Python3+OpenCV2实现图像的几何变换(平移、镜像、缩放、旋转、仿射)
May 13 Python
PyQt5 实现给窗口设置背景图片的方法
Jun 13 Python
python aiohttp的使用详解
Jun 20 Python
Pandas_cum累积计算和rolling滚动计算的用法详解
Jul 04 Python
PyTorch中常用的激活函数的方法示例
Aug 20 Python
python3.6生成器yield用法实例分析
Aug 23 Python
详谈tensorflow gfile文件的用法
Feb 05 Python
Python爬虫之Selenium警告框(弹窗)处理
Dec 04 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
造势之举?韩国总统候选人发布《星际争霸》地图
2017/04/22 星际争霸
php 高效率写法 推荐
2010/02/21 PHP
php遍历文件夹所有文件子文件夹函数代码
2013/11/27 PHP
sae使用smarty模板的方法
2013/12/17 PHP
php获取网页请求状态程序示例
2014/06/17 PHP
JavaScript 图像动画的小demo
2012/05/23 Javascript
js事件冒泡实例分享(已测试)
2013/04/23 Javascript
jQuery点击弹出下拉菜单的小例子
2013/08/01 Javascript
jquery单击事件和双击事件冲突解决方案
2016/03/02 Javascript
jQuery实现点击弹出背景变暗遮罩效果实例代码
2016/06/24 Javascript
jQuery实现级联下拉框实战(5)
2017/02/08 Javascript
JS判断Android、iOS或浏览器的多种方法(四种方法)
2017/06/29 Javascript
用JS编写一个函数,返回数组中重复出现过的元素(实例)
2017/09/14 Javascript
微信小程序富文本渲染引擎的详解
2017/09/30 Javascript
VUE前端cookie简单操作
2017/10/17 Javascript
vue动态路由配置及路由传参的方式
2018/05/23 Javascript
修改vue+webpack run build的路径方法
2018/09/01 Javascript
在Vue项目中使用jsencrypt.js对数据进行加密传输的方法
2019/04/17 Javascript
swiperjs实现导航与tab页的联动
2020/12/13 Javascript
[00:32]2018DOTA2亚洲邀请赛VGJ.T出场
2018/04/03 DOTA
python进阶教程之词典、字典、dict
2014/08/29 Python
Python常用随机数与随机字符串方法实例
2015/04/09 Python
Python PyQt4实现QQ抽屉效果
2018/04/20 Python
python3读取excel文件只提取某些行某些列的值方法
2018/07/10 Python
Python 用matplotlib画以时间日期为x轴的图像
2019/08/06 Python
Python同时迭代多个序列的方法
2020/07/28 Python
Python字符串查找基本操作代码案例
2020/10/27 Python
Giglio美国站:意大利奢侈品购物网
2018/02/10 全球购物
抽象方法、抽象类怎样声明
2014/10/25 面试题
小学毕业感言300字
2014/02/19 职场文书
巾帼文明岗申报材料
2014/05/01 职场文书
赞美老师的演讲稿
2014/05/22 职场文书
校园安全教育心得体会
2016/01/15 职场文书
2016年大学生党员公开承诺书
2016/03/24 职场文书
导游词之秦皇岛燕塞湖
2020/01/03 职场文书
如何让vue长列表快速加载
2021/03/29 Vue.js