提炼 http://south.readthedocs.org/en/latest/tutorial/part1.html 官方手册里面的步骤
在新项目中使用
第一步创建项目
django-admin.py startproject LearnSouth
创建app
django-admin.py startapp books
在learnSouth.settings中修改数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'demo.db', # Or path to database file if using sqlite3.
# The following settings are not used with sqlite3:
'USER': '',
'PASSWORD': '',
'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
'PORT': '', # Set to empty string for default.
}
}
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Uncomment the next line to enable the admin:
# 'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
'south',
'LearnSouth',
'books',
)
命令行执行导入数据库
./manage.py syncdb
初始化迁移信息
./manage.py schemamigration book --initial
执行完以后会在books目录下看到1个migrations文件夹。里面保存了
0001_initial.py 打开看一下。暂时里面没有数据
修改models.py文件内容
from django.db import models
# Create your models here.
class XiaoShuo(models.Model):
create_date = models.DateTimeField(auto_created=True)
public_date = models.DateTimeField(auto_now=True)
title = models.CharField(max_length=128)
contnet = models.CharField(max_length=512000)
class Comment(models.Model):
username = models.CharField(max_length=64)
email = models.CharField(max_length=64)
# email = models.EmailField()
执行
./manage.py schemamigration books --auto
查看migrations目录。发现生成
0002_auto_add_xiaoshuo_add_comment.py文件。代码为
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'XiaoShuo'
db.create_table(u'books_xiaoshuo', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('create_date', self.gf('django.db.models.fields.DateTimeField')()),
('public_date', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
('title', self.gf('django.db.models.fields.CharField')(max_length=128)),
('contnet', self.gf('django.db.models.fields.CharField')(max_length=512000)),
))
db.send_create_signal(u'books', ['XiaoShuo'])
# Adding model 'Comment'
db.create_table(u'books_comment', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('username', self.gf('django.db.models.fields.CharField')(max_length=64)),
('email', self.gf('django.db.models.fields.CharField')(max_length=64)),
))
db.send_create_signal(u'books', ['Comment'])
def backwards(self, orm):
# Deleting model 'XiaoShuo'
db.delete_table(u'books_xiaoshuo')
# Deleting model 'Comment'
db.delete_table(u'books_comment')
models = {
u'books.comment': {
'Meta': {'object_name': 'Comment'},
'email': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '64'})
},
u'books.xiaoshuo': {
'Meta': {'object_name': 'XiaoShuo'},
'contnet': ('django.db.models.fields.CharField', [], {'max_length': '512000'}),
'create_date': ('django.db.models.fields.DateTimeField', [], {}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'public_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
}
}
complete_apps = ['books']
修改models.py代码为
class XiaoShuo(models.Model):
create_date = models.DateTimeField(auto_created=True)
public_date = models.DateTimeField(auto_now=True)
title = models.CharField(max_length=128)
contnet = models.CharField(max_length=512000)
class Comment(models.Model):
username = models.CharField(max_length=64)
email = models.CharField(max_length=64)
# email = models.EmailField()
生成0003_auto_chg_field_comment_email.py
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'Comment.email'
db.alter_column(u'books_comment', 'email', self.gf('django.db.models.fields.EmailField')(max_length=75))
def backwards(self, orm):
# Changing field 'Comment.email'
db.alter_column(u'books_comment', 'email', self.gf('django.db.models.fields.CharField')(max_length=64))
models = {
u'books.comment': {
'Meta': {'object_name': 'Comment'},
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '64'})
},
u'books.xiaoshuo': {
'Meta': {'object_name': 'XiaoShuo'},
'contnet': ('django.db.models.fields.CharField', [], {'max_length': '512000'}),
'create_date': ('django.db.models.fields.DateTimeField', [], {}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'public_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
}
}
complete_apps = ['books']
执行
./manage.py migrate books
些时数据库中是最新的数据了!!!
*********************************************************************************************************
查看sqlite数据库中的内容
当前目录下建立或打开test.db数据库文件,并进入sqlite命令终端,以sqlite>前缀标识:
[cdms@cdms LearnSouth]$ sqlite3 demo.db
查看数据库文件信息命令(注意命令前带字符'.'):
sqlite>.database
查看所有表的创建语句:
sqlite>.schema
*********************************************************************************************************
把修改后的模型合并到字段。
在老项目中使用
首先把south添加到install_apps变量中。
然后执行
./manage.py syncdb
之后执行转换,south会假装执行合并过程
./manage.py convert_to_south myapp
项目拷贝到其他机器上使用的过程中。如果修改提交。必须要执行
./manage.py migrate myapp 0001 --fake
如果没有数据库的项目,则不需要以上步骤。只需要执行syncdb同步到db。
数据迁移
在实践项目中,对模型的的修改往往伴随数据的修改。
比如原有的用户表采用了明文密码。在新版本中需要修改为加密的密码。通常开发过程中需要后台和db的配合。
后台修改字段,db部分在修改。
这里south的强大之处就出来了。可以在代码中修改迁移数据。
注意:一定要备份数据库
下面说说使用demo
首先建立1个app
./manager.py startapp book2
之后在模型里面添加数据
from django.db import models
class User(models.Model):
username = models.CharField(max_length=255)
password = models.CharField(max_length=60)
name = models.TextField()
初始化数据记录
./manage.py schemamigration --initial book2
合并到数据库
./manage.py migrate book2
添加数据
./manage.py shell
User.objects.create(username="andrew", password="ihopetheycantseethis", name="Andrew Godwin")
以上步骤模拟了在实际过程中第一版的开发和数据导入。
接下来更新版本。密码修改为加密部分。
首先修改模型
from django.db import models
# Create your models here.
import hashlib
class User(models.Model):
username = models.CharField(max_length=255)
# password = models.CharField(max_length=60)
password_salt = models.CharField(max_length=8, null=True)
password_hash = models.CharField(max_length=40, null=True)
name = models.TextField()
def check_password(self, password):
return hashlib.sha1(self.password_salt + password).hexdigest() == self.password_hash
执行合并数据库
./manage.py schemamigration book2 --auto
下面是好玩的部分。新建1个数据迁移记录
./manage.py datamigration book2 hash_passwords
在 migrations文件夹下面生成1份0003_hash_password.py文件。
修改forwards函数。
def forwards(self, orm):
"Write your forwards methods here."
# Note: Don't use "from appname.models import ModelName".
# Use orm.ModelName to refer to models in this application,
# and orm['appname.ModelName'] for models in other applications.
import random, hashlib, string
for user in orm.User.objects.all():
user.password_salt = "".join([random.choice(string.letters) for i in range(8)])
user.password_hash = hashlib.sha1(user.password_salt + user.password).hexdigest()
user.save()
forwards函数里面。执行了修改密码,导入部分。
回退函数也修改
def backwards(self, orm):
"Write your backwards methods here."
raise RuntimeError("cannot reverse this migration.")
接下来删除models.py中原始的password字段。
执行合并
outekiMacBook-Air:LearnSouth watsy$ ./manage.py schemamigration book2 --auto
/Users/watsy/Documents/code/gitoschina/python/LearnSouth/book2/models.py:7: DeprecationWarning: the sha module is deprecated; use the hashlib module instead
import sha
? The field 'User.password' does not have a default specified, yet is NOT NULL.
? Since you are removing this field, you MUST specify a default
? value to use for existing rows. Would you like to:
? 1. Quit now, and add a default to the field in models.py
? 2. Specify a one-off value to use for existing columns now
? 3. Disable the backwards migration by raising an exception.
? Please select a choice: 2
? Please enter Python code for your one-off default value.
? The datetime module is available, so you can do e.g. datetime.date.today()
>>> ""
- Deleted field password on book2.User
Created 0004_auto__del_field_user_password.py. You can now apply this migration with: ./manage.py migrate book2
执行合并到数据库
outekiMacBook-Air:LearnSouth watsy$ ./manage.py migrate book2
/Users/watsy/Documents/code/gitoschina/python/LearnSouth/book2/models.py:7: DeprecationWarning: the sha module is deprecated; use the hashlib module instead
import sha
Running migrations for book2:
- Migrating forwards to 0004_auto__del_field_user_password.
> book2:0002_auto__add_field_user_password_salt__add_field_user_password_hash
> book2:0003_hash_passwords
- Migration 'book2:0003_hash_passwords' is marked for no-dry-run.
> book2:0004_auto__del_field_user_password
- Loading initial data for book2.
Installed 0 object(s) from 0 fixture(s)
测试执行以后的数据库是否修改密码成功
outekiMacBook-Air:LearnSouth watsy$ ./manage.py shell
>>> from book2.models import User
>>> User.objects.get(id=1).check_password("258841679")
True
>>> User.objects.get(id=1).check_password("fakepass")
False
测试修改成功~