django south 使用教程(2)

一、迁移清单

列出某个app下的迁移清单,或整个django项目的迁移清单,相当于列出其历史记录,这时要用到

#某个app下迁移清单

manage.py migrate app_name --list

#整个项目迁移清单

manage.py migrate --list

显示如下。注意带*的为已经应用到了 ,()表示尚未应用到的。

E:\project\demo>manage.py migrate other --list



 other

  (*) 0001_initial

  (*) 0002_auto__add_action__del_field_contact_age__add_field_contact_comment

  (*) 0003_initial

  (*) 0004_initial

  (*) 0005_initial

  (*) 0006_auto__add_field_contact_website

  (*) 0007_auto__add_unique_contact_name

  (*) 0008_auto__add_field_action_keys

  (*) 0009_auto__del_field_action_keys

  (*) 0010_auto__del_action

二、数据迁移

第一节所涉及的是模式迁移,涉及表、字段、索引的添加和删除;另一种迁移就是数据迁移。

数据迁移是用来改变你的数据库中存储的数据匹配一个新的模式,或特性。

例如,如果你一直以纯文本形式保存密码,现在你需要以利用salt对密码进行散列 的形式,这样就涉及到数据的迁移以适应新的模式。可能有以下三个步骤(每个步骤对应一个迁移):

(1)、创建两列:password_salt password_hash (a schema migration).

(2)、使用旧密码的列的内容,计算每个用户的密码后应用到新的列(a data migration)

(3)、移除旧的密码列(a schema migration).

class User(models.Model):

    username = models.CharField(max_length=255)

    password = models.CharField(max_length=60)

假设有用户:Jack,密码:admin123.如果以文本的形式肯定不安全了,那么现在就利用salt对密码进行散列

import sha

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)

    

    def check_password(self, password):

        return sha.sha(self.password_salt+password).hexdigest() == self.password_hash

    

"""

用户注册的过程:

1)用户提供密码(以及其他用户信息);

2)系统为用户生成Salt值;

3)系统将Salt值和用户密码连接到一起;

4)对连接后的值进行散列,得到Hash值;

5)将Hash值和Salt值分别放到数据库中。



用户登录的过程:

1)用户提供用户名和密码;

2)系统通过用户名找到与之对应的Hash值和Salt值;

3)系统将Salt值和用户提供的密码连接到一起;

4)对连接后的值进行散列,得到Hash'(注意有个“撇”);

5)比较Hash和Hash'是否相等,相等则表示密码正确,否则表示密码错误。

"""

接下来就是创建模式迁移将会创建两列:

E:\project\demo>manage.py schemamigration other --auto

 + Added field password_salt on other.User

 + Added field password_hash on other.User

Created 0013_auto__add_field_user_password_salt__add_field_user_password_hash.py

. You can now apply this migration with: ./manage.py migrate other

那么接下来就是创建数据迁移了,

E:\project\demo>manage.py datamigration other hash_passwords

Created 0014_hash_passwords.py.

打开 0014_hash_passwords.py 文件 发现如下,我们还需要手写forwards、backwards方法

django south 使用教程(2)

更改如下:

# -*- coding: utf-8 -*-

import datetime

from south.db import db

from south.v2 import DataMigration

from django.db import models



class Migration(DataMigration):



    def forwards(self, orm):

        import random,sha,string

        for user in orm.User.objects.all():

            #更新数据

            user.password_salt = "".join([random.choice(string.letters) for i in range(8)])

            user.password_hash = sha.sha(user.password_salt + user.password).hexdigest()

            user.save()

        

    def backwards(self, orm):

        raise RuntimeError("Cannot reverse this migration.")



    ......

注意这里的orm.User,对象关系映射(Object Relational Mapping) 这里关系到其迁移的model,如User model。如果用数据迁移中使用其他app的model则用orm['contenttypes.ContentType']. Models

If you want to access models from other apps in your data migration, use a syntax like orm['contenttypes.ContentType']. Models will be available if you can somehow get to them via ForeignKey or ManyToMany traversal from your app’s models; if you want to freeze other models, simply pass --freeze appname on the datamigration command line.

最后在backwards()方法中引发错误,因为这个过程本质上是不可逆转的。就是说只能向前迁移,不能向后。

最后步骤:删除password字段,启动迁移

E:\project\demo>manage.py schemamigration other --auto

 ? 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.

 ?  2. Specify a one-off value to use for existing columns now

 ?  3. Disable the backwards migration by raising an exception; you can edit the

 migration to fix it later

 ? 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 other.User

Created 0015_auto__del_field_user_password.py. You can now apply this migration

with: ./manage.py migrate other

接下来就是应用这3个迁移:

E:\project\demo>manage.py migrate other

Running migrations for other:

 - Migrating forwards to 0004_auto__del_field_user_password.

 > southtut2:0002_auto__add_field_user_password_salt__add_field_user_password_hash

 > southtut2:0003_hash_passwords

 > southtut2:0004_auto__del_field_user_password

 - Loading initial data for other.

接下来验证一下:

>>> from other.models import User

>>> User.objects.get(id=1).check_password('admin123')

True

>>> User.objects.get(id=1).check_password('admin3')

False

django south 使用教程(2)

 

 

 

你可能感兴趣的:(django)