34

サイトのすべてのユーザーを破棄したくありません。しかし、私は Django 1.5 のカスタム プラグ可能なユーザー モデルを利用したいと考えています。これが私の新しいユーザーモデルです:

class SiteUser(AbstractUser):
    site = models.ForeignKey(Site, null=True)

新しいインストールでは、すべてが新しいモデルで動作します (他のコードと、これを実行する正当な理由があります。これらはすべて、ここでは関係ありません)。しかし、これをライブ サイトに配置して syncdb & migrate すると、すべてのユーザーが失われるか、少なくとも、新しいモデル用に作成された新しいテーブルとは別の孤立したテーブルに配置されます。

私は South に精通していますが、この投稿と私の一部の試行に基づいて、そのデータ移行は現在、この特定の移行には適していないようです. そのため、South をこれまたは South 以外の移行 (生の SQL、dumpdata/loaddata など) で機能させる方法を探しています。これを各サーバー (Postgres 9.2) で実行してユーザーを移行できます。古い auth.User テーブルがまだデータベースにある間に、新しいテーブルが作成されたら。

4

5 に答える 5

49

サウスはあなたのためにこの移行を行うことができますが、賢く段階的に行う必要があります. ステップバイステップのガイドは次のとおりです: (このガイドではAbstractUser、 ではなくをサブクラス化することを前提としていますAbstractBaseUser)

  1. 切り替えを行う前に、カスタム ユーザー モデルを含むアプリケーションでサウス サポートが有効になっていることを確認してください (ガイドのために、それaccountsをモデルと呼びますUser)。この時点では、まだカスタム ユーザー モデルを作成していません。

    $ ./manage.py schemamigration accounts --initial
    Creating migrations directory at 'accounts/migrations'...
    Creating __init__.py in 'accounts/migrations'...
    Created 0001_initial.py.
    
    $ ./manage.py migrate accounts [--fake if you've already syncdb'd this app]
     Running migrations for accounts:
     - Migrating forwards to 0001_initial.
     > accounts:0001_initial
     - Loading initial data for accounts.
    
  2. アカウント アプリで新しい空白のユーザー移行を作成します。

    $ ./manage.py schemamigration accounts --empty switch_to_custom_user
    Created 0002_switch_to_custom_user.py.
    
  3. アプリでカスタムUserモデルを作成しますaccountsが、次のように定義されていることを確認してください。

    class SiteUser(AbstractUser): pass
    
  4. 空白の移行に次のコードを入力します。

    # encoding: utf-8
    from south.db import db
    from south.v2 import SchemaMigration
    
    class Migration(SchemaMigration):
    
        def forwards(self, orm):
            # Fill in the destination name with the table name of your model
            db.rename_table('auth_user', 'accounts_user')
            db.rename_table('auth_user_groups', 'accounts_user_groups')
            db.rename_table('auth_user_user_permissions', 'accounts_user_user_permissions')
    
        def backwards(self, orm):
            db.rename_table('accounts_user', 'auth_user')
            db.rename_table('accounts_user_groups', 'auth_user_groups')
            db.rename_table('accounts_user_user_permissions', 'auth_user_user_permissions')
    
        models = { ....... } # Leave this alone
    
  5. 移行を実行する

    $ ./manage.py migrate accounts
     - Migrating forwards to 0002_switch_to_custom_user.
     > accounts:0002_switch_to_custom_user
     - Loading initial data for accounts.
    
  6. ここでユーザー モデルに変更を加えます。

    # settings.py
    AUTH_USER_MODEL = 'accounts.User'
    
    # accounts/models.py
    class SiteUser(AbstractUser):
        site = models.ForeignKey(Site, null=True)
    
  7. この変更の移行を作成して実行する

    $ ./manage.py schemamigration accounts --auto
     + Added field site on accounts.User
    Created 0003_auto__add_field_user_site.py.
    
    $ ./manage.py migrate accounts
     - Migrating forwards to 0003_auto__add_field_user_site.
     > accounts:0003_auto__add_field_user_site
     - Loading initial data for accounts.
    

正直なところ、セットアップについて十分な知識があり、既に南を使用している場合は、アカウント モジュールに次の移行を追加するだけで簡単に実行できます。

# encoding: utf-8
from south.db import db
from south.v2 import SchemaMigration
from django.db import models

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Fill in the destination name with the table name of your model
        db.rename_table('auth_user', 'accounts_user')
        db.rename_table('auth_user_groups', 'accounts_user_groups')
        db.rename_table('auth_user_permissions', 'accounts_user_permissions')
        # == YOUR CUSTOM COLUMNS ==
        db.add_column('accounts_user', 'site_id',
            models.ForeignKey(orm['sites.Site'], null=True, blank=False)))

    def backwards(self, orm):
        db.rename_table('accounts_user', 'auth_user')
        db.rename_table('accounts_user_groups', 'auth_user_groups')
        db.rename_table('accounts_user_user_permissions', 'auth_user_user_permissions')
        # == YOUR CUSTOM COLUMNS ==
        db.remove_column('accounts_user', 'site_id')

    models = { ....... } # Leave this alone

EDIT 2/5/13: auth_user_group テーブルの名前変更を追加。データベースの制約により、FK は正しいテーブルを指すように自動更新されますが、M2M フィールドのテーブル名は 2 つのエンド テーブルの名前から生成されるため、この方法で手動で更新する必要があります。

EDIT 2: @Tuttle と @pix0r の修正に感謝します。

于 2013-02-25T02:49:34.917 に答える
16

これを行う私の信じられないほど怠惰な方法:

  1. AbstractUser を拡張して、新しいモデル (ユーザー) を作成します。新しいモデル内の Meta で、db_table をオーバーライド、「auth_user」に設定します。

  2. South を使用して初期移行を作成します。

  3. 移行しますが、移行の実行時に使用して、移行を偽装し--fakeます。

  4. 新しいフィールドを追加し、移行を作成し、通常どおり実行します。

これは怠け者ではありませんが、機能します。これで、ユーザーの古いテーブルを使用するだけの 1.5 準拠のユーザー モデルができました。適切な移行履歴もあります。

これは、後で手動で移行してテーブルの名前を変更することで修正できます。

于 2013-02-25T06:47:59.580 に答える
4

南のような移行フレームワークがここに行く正しい方法であることを正しく認識していると思います。South を使用していると仮定すると、 Data Migrations機能を使用して古いユーザーを新しいモデルに移植できるはずです。

具体的にはforwards、ユーザー テーブルのすべての行を新しいテーブルにコピーするメソッドを追加します。次のようなもの:

def forwards(self, orm):
    for user in orm.User.objects.all():
        new_user = SiteUser(<initialize your properties here>)
        new_user.save()

このメソッドを使用して、bulk_create処理を高速化することもできます。

于 2013-02-15T22:11:16.577 に答える
3

South と格闘するのにうんざりしていたので、実際にはこれを別の方法で行うことになり、私の特定の状況ではうまくいきました。

まず、./manage.py dumpdata で動作させ、ダンプを修正してから、./manage.py loaddata で動作させました。その後、必要な django 設定のみをロードし、シリアライゼーション/デシリアライゼーションを直接実行する単一の自己完結型スクリプトを使用して、基本的に同じことができることに気付きました。

自己完結型の Python スクリプト

## userconverter.py ##

import json
from django.conf import settings

settings.configure(
    DATABASES={ 
            # copy DATABASES configuration from your settings file here, or import it directly from your settings file (but not from django.conf.settings) or use dj_database_url
            },
    SITE_ID = 1, # because my custom user implicates contrib.sites (which is why it's in INSTALLED_APPS too)
    INSTALLED_APPS = ['django.contrib.sites', 'django.contrib.auth', 'myapp'])

# some things you have to import after you configure the settings
from django.core import serializers
from django.contrib.auth.models import User

# this isn't optimized for huge amounts of data -- use streaming techniques rather than loads/dumps if that is your case
old_users = json.loads(serializers.serialize('json', User.objects.all()))
for user in old_users:
    user['pk'] = None
    user['model'] = "myapp.siteuser"
    user['fields']["site"] = settings['SITE_ID']

for new_user in serializers.deserialize('json', json.dumps(old_users)):
    new_user.save()

ダンプデータ/ロードデータを使用

私は次のことをしました:

1) ./manage.py dumpdata auth.User

2) auth.user データを新しいユーザーに変換するスクリプト。(または、お気に入りのテキストエディタまたはgrepで手動で検索して置換するだけです)私のものは次のようになりました:

def convert_user_dump(filename, site_id):
    file = open(filename, 'r')
    contents = file.read()
    file.close()
    user_list = json.loads(contents)
    for user in user_list:
        user['pk'] = None  # it will auto-increment
        user['model'] = "myapp.siteuser"
        user['fields']["site"] = side_id
    contents = json.dumps(user_list)
    file = open(filename, 'w')
    file.write(contents)
    file.close()

3) ./manage.py ロードデータ ファイル名

4) AUTH_USER_MODEL を設定する

*補足: このタイプの移行を行う際の重要な部分の 1 つは、使用する手法 (South、シリアル化/変更/逆シリアル化、またはその他) に関係なく、現在の設定で AUTH_USER_MODEL をカスタム モデルに設定するとすぐに、django です。テーブルがまだ存在していても、auth.User から切り離します。*

于 2013-02-25T17:33:39.797 に答える