通过数据库向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 相关文章推荐
pyv8学习python和javascript变量进行交互
Dec 04 Python
python实现Decorator模式实例代码
Feb 09 Python
python爬虫爬取淘宝商品信息(selenum+phontomjs)
Feb 24 Python
JavaScript实现一维数组转化为二维数组
Apr 17 Python
Pyqt5 实现跳转界面并关闭当前界面的方法
Jun 19 Python
django搭建项目配置环境和创建表过程详解
Jul 22 Python
python字典的常用方法总结
Jul 31 Python
python-Web-flask-视图内容和模板知识点西宁街
Aug 23 Python
python网络爬虫 Scrapy中selenium用法详解
Sep 28 Python
如何修复使用 Python ORM 工具 SQLAlchemy 时的常见陷阱
Nov 19 Python
pytorch-神经网络拟合曲线实例
Jan 15 Python
Idea安装python显示无SDK问题解决方案
Aug 12 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
以文本方式上传二进制文件的PHP程序
2006/10/09 PHP
PHP+javascript液晶时钟
2006/10/09 PHP
php中fgetcsv()函数用法实例
2014/11/28 PHP
ThinkPHP入口文件设置及相关注意事项分析
2014/12/05 PHP
jquery通过select列表选择框对表格数据进行过滤示例
2014/05/07 Javascript
javascript如何操作HTML下拉列表标签
2015/08/20 Javascript
JavaScript Split()方法
2015/12/18 Javascript
使用AJAX实现Web页面进度条的实例分享
2016/05/06 Javascript
JS实现DOM删除节点操作示例
2018/04/04 Javascript
opencv 识别微信登录验证滑动块位置
2018/08/07 Javascript
详解如何搭建mpvue框架搭配vant组件库的小程序项目
2019/05/16 Javascript
nodejs 递归拷贝、读取目录下所有文件和目录
2019/07/18 NodeJs
微信小程序实现收货地址左滑删除
2020/11/18 Javascript
layui上传图片到服务器的非项目目录下的方法
2019/09/26 Javascript
Vue仿Bibibili首页的问题
2021/01/21 Vue.js
Python实现端口复用实例代码
2014/07/03 Python
Python 数据处理库 pandas进阶教程
2018/04/21 Python
python内置数据类型之列表操作
2018/11/12 Python
Python 中 -m 的典型用法、原理解析与发展演变
2019/11/11 Python
django自定义模板标签过程解析
2019/12/14 Python
使用Pandas将inf, nan转化成特定的值
2019/12/19 Python
python 微信好友特征数据分析及可视化
2020/01/07 Python
使用Puppeteer爬取微信文章的实现
2020/02/11 Python
移动web模拟客户端实现多方框输入密码效果【附代码】
2016/03/25 HTML / CSS
恒华伟业笔试面试题
2015/02/26 面试题
办公室前台的岗位职责
2013/12/20 职场文书
自主实习接收函
2014/01/13 职场文书
宣传部部长竞选演讲稿
2014/04/26 职场文书
学雷锋树新风演讲稿
2014/05/10 职场文书
大学社团招新的通讯稿
2014/09/10 职场文书
法律专业大学生职业生涯规划书:向目标一步步迈进
2014/09/22 职场文书
考试作弊被抓检讨书
2014/10/02 职场文书
乡镇群众路线专项整治方案
2014/11/03 职场文书
幼儿园教师师德承诺书
2015/04/28 职场文书
2015年污水处理厂工作总结
2015/05/26 职场文书
《实心球》教学反思
2016/02/23 职场文书