通过数据库向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文件和目录操作函数小结
Jul 11 Python
使用优化器来提升Python程序的执行效率的教程
Apr 02 Python
使用Python判断质数(素数)的简单方法讲解
May 05 Python
python字典操作实例详解
Nov 16 Python
详解python string类型 bytes类型 bytearray类型
Dec 16 Python
Python使用gRPC传输协议教程
Oct 16 Python
linux下安装python3和对应的pip环境教程详解
Jul 01 Python
使用python和pygame制作挡板弹球游戏
Dec 03 Python
浅谈pytorch、cuda、python的版本对齐问题
Jan 15 Python
使用PyQt5实现图片查看器的示例代码
Apr 21 Python
Python基于BeautifulSoup爬取京东商品信息
Jun 01 Python
简单介绍Python的第三方库yaml
Jun 18 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 UTF8 文件的签名问题
2009/10/30 PHP
PHP闭包(Closure)使用详解
2013/05/02 PHP
微信公众号判断用户是否已关注php代码解析
2016/06/24 PHP
ThinkPHP框架实现导出excel数据的方法示例【基于PHPExcel】
2018/05/12 PHP
javascript css在IE和Firefox中区别分析
2009/02/18 Javascript
如何在node的express中使用socket.io
2014/12/15 Javascript
JS实现向表格中动态添加行的方法
2015/03/30 Javascript
jQuery实现平滑滚动的标签分栏切换效果
2015/08/28 Javascript
详解Javascript中prototype属性(推荐)
2016/09/03 Javascript
JavaScript实现经典排序算法之插入排序
2016/12/28 Javascript
Angular模板表单校验方法详解
2017/08/11 Javascript
BootStrap给table表格的每一行添加一个按钮事件
2017/09/07 Javascript
深入理解ES6之数据解构的用法
2018/01/13 Javascript
分享ES6的7个实用技巧
2018/01/18 Javascript
浅析vue-router jquery和params传参(接收参数)$router $route的区别
2018/08/03 jQuery
ES10 特性的完整指南小结
2019/03/04 Javascript
ES6 Map结构的应用实例分析
2019/06/26 Javascript
Node.js之删除文件夹(含递归删除)代码实例
2019/09/09 Javascript
如何在VUE中使用vue-awesome-swiper
2021/01/04 Vue.js
Node.js 中如何收集和解析命令行参数
2021/01/08 Javascript
[00:59]DOTA2英雄背景故事——上古巨神
2020/06/28 DOTA
举例讲解Python中装饰器的用法
2015/04/27 Python
python制作最美应用的爬虫
2015/10/28 Python
Python 网络爬虫--关于简单的模拟登录实例讲解
2018/06/01 Python
Python使用folium excel绘制point
2019/01/03 Python
Python玩转PDF的各种骚操作
2019/05/06 Python
在pycharm下设置自己的个性模版方法
2019/07/15 Python
Django组件content-type使用方法详解
2019/07/19 Python
施华洛世奇加拿大官网:SWAROVSKI加拿大
2018/06/03 全球购物
设计师大码女装:11 Honoré
2020/05/03 全球购物
心碎乌托邦的创业计划书范文
2013/12/26 职场文书
财务总经理岗位职责
2014/02/16 职场文书
大学生两会学习心得体会
2014/03/10 职场文书
党员干部承诺书
2014/03/25 职场文书
金融系应届毕业生求职信
2014/05/26 职场文书
介绍信怎么写
2015/01/30 职场文书