私は自分のサイトのすべてのユーザーを破壊したくない。しかし、私はDjango 1.5のカスタムプラグ可能なユーザーモデルを利用したいと思います。これが私の新しいユーザーモデルです:
class SiteUser(AbstractUser):
site = models.ForeignKey(Site, null=True)
すべてが新しいインストールで私の新しいモデルで動作します(これを行う正当な理由とともに、他のコードがあります-これらはすべてここでは関係ありません)。しかし、これをライブサイトに配置し、syncdb&migrateを実行すると、すべてのユーザーが失われるか、少なくとも、新しいモデル用に作成された新しいテーブルとは異なる孤立したテーブルになります。
私はSouthに精通していますが、 この投稿 と私の側のいくつかの試行に基づいて、そのデータ移行は現在この特定の移行に適合していないようです。そのため、これに対してSouthを機能させる方法、または各サーバー(Postgres 9.2)で実行してユーザーを移行できるSouth以外の移行(raw SQL、dumpdata/loaddataなど)を行う方法を探しています。古いauth.Userテーブルがまだデータベースにある間に、新しいテーブルが作成された後。
サウスはあなたのためにこの移行を行うことができる以上のものですが、あなたは賢く、段階的にそれを行う必要があります。ステップバイステップガイドは次のとおりです:(このガイドでは、AbstractUser
ではなくAbstractBaseUser
をサブクラス化することを前提としています)
切り替えを行う前に、カスタムユーザーモデルを含むアプリケーションでサウスサポートが有効になっていることを確認してください(ガイドのために、これを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.
アカウントアプリで新しい空白のユーザー移行を作成します。
$ ./manage.py schemamigration accounts --empty switch_to_custom_user
Created 0002_switch_to_custom_user.py.
User
アプリでカスタムaccounts
モデルを作成しますが、次のように定義されていることを確認してください。
class SiteUser(AbstractUser): pass
空白の移行に次のコードを入力します。
# 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
移行を実行する
$ ./manage.py migrate accounts
- Migrating forwards to 0002_switch_to_custom_user.
> accounts:0002_switch_to_custom_user
- Loading initial data for accounts.
今すぐユーザーモデルに変更を加えてください。
# settings.py
AUTH_USER_MODEL = 'accounts.User'
# accounts/models.py
class SiteUser(AbstractUser):
site = models.ForeignKey(Site, null=True)
この変更の移行を作成して実行します
$ ./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
編集2/5/13:auth_user_groupテーブルの名前変更を追加しました。 FKは、dbの制約により正しいテーブルを指すように自動更新されますが、M2Mフィールドのテーブル名は、2つのエンドテーブルの名前から生成されるため、この方法で手動で更新する必要があります。
編集2:訂正してくれた@Tuttleと@ pix0rに感謝します。
これを行う私の信じられないほど怠惰な方法:
AbstractUserを拡張して、新しいモデル(User)を作成します。新しいモデル内で、そのメタで、 db_table をオーバーライドし、「auth_user」に設定します。
Southを使用して初期移行を作成します。
移行しますが、移行の実行時に--fake
を使用して、移行を偽造します。
新しいフィールドを追加し、移行を作成して、通常どおり実行します。
これは怠惰を超えていますが、機能します。これで、1.5準拠のユーザーモデルができました。これは、古いユーザーテーブルのみを使用します。また、適切な移行履歴があります。
後で手動で移行してテーブルの名前を変更することで、これを修正できます。
私は南との闘いにうんざりしていたので、実際にはこれを別の方法で行うことになり、特定の状況でうまくいきました。
最初に、。/ manage.py dumpdataで動作させてダンプを修正し、次に./manage.pyloaddataで動作させました。次に、必要なDjango設定のみをロードし、シリアル化/逆シリアル化を直接実行する、単一の自己完結型スクリプトで基本的に同じことができることに気付きました。
## 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.pyloaddataファイル名
4)AUTH_USER_MODELを設定します
*補足:使用する手法(南、シリアル化/変更/逆シリアル化など)に関係なく、このタイプの移行を行う上で重要な部分の1つは、現在の設定でAUTH_USER_MODELをカスタムモデルに設定するとすぐに= Djangoテーブルがまだ存在している場合でも、auth.Userから切り離されます。*
Southのような移行フレームワークがここに行く正しい方法であることを正しく識別したと思います。 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
メソッドを使用して処理を高速化することもできます。
Django 1.6/Django-CMS 3プロジェクトで、カスタムユーザーモデルに切り替えることにしました。データベースに失いたくないデータがあったため、おそらく少し遅れました(一部のCMSページなど)。
AUTH_USER_MODELをカスタムモデルに切り替えた後、他の多くのテーブルに、削除されなかった古いauth_user
テーブルへの外部キーがあったため、予期していなかった多くの問題が発生しました。そのため、表面的には機能しているように見えますが、ページの公開、ページへの画像の追加、ユーザーの追加など、auth_user
への外部キーがまだあるテーブルにエントリを作成しようとしたため、多くのことがうまくいきませんでした。実際に一致するレコードをauth_user
に挿入します。
すべてのテーブルとリレーションを再構築し、古いデータを(ユーザーを除いて)コピーするための迅速で汚い方法を見つけました。
mysqldump
を使用してデータベースの完全バックアップを実行しますCREATE TABLE
ステートメントを使用せずに別のバックアップを実行し、再構築後に存在しないか、新しいデータベースにsyncdb --migrate
が入力されるいくつかのテーブルを除外します:south_migrationhistory
auth_user
auth_user_groups
auth_user_user_permissions
auth_permission
Django_content_types
Django_site
manage.py syncdb --migrate
)(MySQLの場合)実行したコマンドは次のとおりです。
mysqldump <database> > ~/full-backup.sql
mysqldump <database> \
--no-create-info \
--ignore-table=<database>.south_migrationhistory \
--ignore-table=<database>.auth_user \
--ignore-table=<database>.auth_user_groups \
--ignore-table=<database>.auth_user_user_permissions \
--ignore-table=<database>.auth_permission \
--ignore-table=<database>.Django_content_types \
--ignore-table=<database>.Django_site \
> ~/data-backup.sql
./manage.py sqlclear
./manage.py syncdb --migrate
mysqldump <database> > ~/empty-database.sql
./manage.py dbshell < ~/data-backup.sql
(edit ~/data-backup.sql to remove data dumped from a table that no longer exists)
./manage.py dbshell < ~/empty-database.sql
./manage.py dbshell < ~/data-backup.sql
(repeat until clean)