django第三方类库 - django-south 项目开始中就使用south方法

来源:互联网 发布:上海网络推广招聘 编辑:程序博客网 时间:2024/04/30 12:10

提炼 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 datetimefrom south.db import dbfrom south.v2 import SchemaMigrationfrom django.db import modelsclass 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

把修改后的模型合并到字段。


在老项目中使用

首先把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 modelsclass 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 shellUser.objects.create(username="andrew", password="ihopetheycantseethis", name="Andrew Godwin")

以上步骤模拟了在实际过程中第一版的开发和数据导入。

接下来更新版本。密码修改为加密部分。

首先修改模型

from django.db import models# Create your models here.import hashlibclass 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.UserCreated 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 shaRunning 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

测试修改成功~

原创粉丝点击