I'd prefer not to destroy all the users on my site. But I want to take advantage of Django 1.5's custom pluggable user model. Here's my new user model:
我不想毁掉我网站上所有的用户。但是我想利用Django 1.5的自定义可插拔用户模型。这是我的新用户模型:
class SiteUser(AbstractUser):
site = models.ForeignKey(Site, null=True)
Everything works with my new model on a new install (I've got other code, along with a good reason for doing this--all of which are irrelevant here). But if I put this on my live site and syncdb & migrate, I'll lose all my users or at least they'll be in a different, orphaned table than the new table created for my new model.
在新的安装中,我的新模型都可以工作(我有其他的代码,以及这样做的一个很好的理由——所有这些在这里都是不相关的)。但是如果我把这个放到我的live站点上,并进行syncdb和migration,我将会失去所有的用户,或者至少他们会在一个不同的孤立的表中,而不是为我的新模型创建的新表。
I'm familiar with South, but based on this post and some trials on my part, it seems its data migrations are not currently a fit for this specific migration. So I'm looking for some way to either make South work for this or for some non-South migration (raw SQL, dumpdata/loaddata, or otherwise) that I can run on each of my servers (Postgres 9.2) to migrate the users once the new table has been created while the old auth.User table is still in the database.
我对South很熟悉,但是基于这篇文章和我的一些尝试,它的数据迁移目前似乎并不适合这个特定的迁移。因此,我正在寻找一种方法,要么让South工作于此,要么进行一些非South迁移(原始SQL、dumpdata/loaddata或其他),以便在创建新表的同时在旧的auth上运行每个服务器(Postgres 9.2),以迁移用户。用户表仍然在数据库中。
5 个解决方案
#1
47
South is more than able to do this migration for you, but you need to be smart and do it in stages. Here's the step-by-step guide: (This guide presupposed you subclass AbstractUser
, not AbstractBaseUser
)
South能够为您完成这种迁移,但是您需要聪明地分阶段进行迁移。以下是一步一步的指南:(本指南假定您是AbstractUser的子类,而不是AbstractBaseUser)
-
Before making the switch, make sure that south support is enabled in the application that contains your custom user model (for the sake of the guide, we'll call it
accounts
and the modelUser
). At this point you should not yet have a custom user model.在进行切换之前,请确保在包含自定义用户模型的应用程序中启用了south支持(出于对指南的考虑,我们将其称为accounts和model 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.
-
Create a new, blank user migration in the accounts app.
在accounts应用程序中创建一个新的空白用户迁移。
$ ./manage.py schemamigration accounts --empty switch_to_custom_user Created 0002_switch_to_custom_user.py.
-
Create your custom
User
model in theaccounts
app, but make sure it is defined as:在accounts应用程序中创建您的自定义用户模型,但要确保它定义为:
class SiteUser(AbstractUser): pass
-
Fill in the blank migration with the following code.
用以下代码填充空白迁移。
# 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
-
Run the migration
运行迁移
$ ./manage.py migrate accounts - Migrating forwards to 0002_switch_to_custom_user. > accounts:0002_switch_to_custom_user - Loading initial data for accounts.
-
Make any changes to your user model now.
现在对您的用户模型做任何更改。
# settings.py AUTH_USER_MODEL = 'accounts.User' # accounts/models.py class SiteUser(AbstractUser): site = models.ForeignKey(Site, null=True)
-
create and run migrations for this change
创建并运行此更改的迁移
$ ./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.
Honestly, If you already have good knowledge of your setup and already use south, It should be as simple as adding the following migration to your accounts module.
老实说,如果您已经非常了解您的设置并已经使用了south,那么只需将以下迁移添加到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: added rename for auth_user_group table. FKs will auto update to point at the correct table due to db constraints, but M2M fields' table names are generated from the names of the 2 end tables and will need manual updating in this manner.
编辑2/5/13:添加了auth_user_group表的重命名。FKs由于db限制会自动更新到正确的表,但是M2M字段的表名是由两个结束表的名称生成的,需要手动更新。
EDIT 2: Thanks to @Tuttle & @pix0r for the corrections.
编辑2:感谢@Tuttle & @pix0r修正。
#2
15
My incredibly lazy way of doing this:
我非常懒惰的方法是:
-
Create a new model (User), extending AbstractUser. Within new model, in it's Meta, override db_table and set to 'auth_user'.
创建一个新的模型(用户),扩展AbstractUser。在新模型中,在它的Meta中,重写db_table并设置为“auth_user”。
-
Create an initial migration using South.
使用南方创建初始迁移。
-
Migrate, but fake the migration, using
--fake
when running migrate.迁移,但是伪造迁移,使用——在运行迁移时伪造。
-
Add new fields, create migration, run it normally.
添加新字段,创建迁移,正常运行。
This is beyond lazy, but works. You now have a 1.5 compliant User model, which just uses the old table of users. You also have a proper migration history.
这不是懒惰,而是工作。现在您有了一个兼容1.5的用户模型,它只使用旧的用户表。您还有一个合适的迁移历史。
You can fix this later on with manual migrations to rename the table.
稍后您可以通过手动迁移来修复这个问题,以重命名表。
#3
4
I think you've correctly identified that a migration framework like South is the right way to go here. Assuming you're using South, you should be able to use the Data Migrations functionality to port the old users to your new model.
我想你已经正确地认识到,像南方这样的迁移框架是正确的。假设您正在使用South,那么您应该能够使用数据迁移功能将旧用户移植到新模型。
Specifically, I would add a forwards
method to copy all rows in your user table to the new table. Something along the lines of:
具体地说,我将添加一个forward方法,将用户表中的所有行复制到新表中。类似于:
def forwards(self, orm):
for user in orm.User.objects.all():
new_user = SiteUser(<initialize your properties here>)
new_user.save()
You could also use the bulk_create
method to speed things up.
您还可以使用bulk_create方法来加快速度。
#4
4
I got tired of struggling with South so I actually ended up doing this differently and it worked out nicely for my particular situation:
我厌倦了与南方的斗争,所以我最终做了不同的事情,它很适合我的特殊情况:
First, I made it work with ./manage.py dumpdata, fixing up the dump, and then ./manage.py loaddata, which worked. Then I realized I could do basically the same thing with a single, self-contained script that only loads necessary django settings and does the serialization/deserialization directly.
首先,我让它工作。py dumpdata,修复转储,然后。/管理。py loaddata,工作。然后我意识到我可以用一个独立的脚本做同样的事情,这个脚本只加载必要的django设置并直接执行序列化/反序列化。
Self-contained python script
## 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()
With dumpdata/loaddata
I did the following:
我做了以下几点:
1) ./manage.py dumpdata auth.User
1)。/管理。py dumpdata auth.User
2) Script to convert auth.user data to new user. (or just manually search and replace in your favorite text editor or grep) Mine looked something like:
2)转换auth的脚本。向新用户提供用户数据。(或者只是手工搜索和替换您最喜欢的文本编辑器或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 loaddata filename
3)。/管理。py loaddata文件名
4) set AUTH_USER_MODEL
4)设置AUTH_USER_MODEL
*Side Note: One critical part of doing this type of migration, regardless of which technique you use (South, serialization/modification/deserialization, or otherwise) is that as soon as you set AUTH_USER_MODEL to your custom model in the current settings, django cuts you off from auth.User, even if the table still exists.*
*附加说明:进行这种类型迁移的一个关键部分是,只要在当前设置中将AUTH_USER_MODEL设置为自定义模型,django就会切断您与auth的连接。用户,即使该表仍然存在。*。
#5
2
We decided to switch to a custom user model in our Django 1.6/Django-CMS 3 project, perhaps a little bit late because we had data in our database that we didn't want to lose (some CMS pages, etc).
我们决定在Django 1.6/Django-CMS 3项目中切换到自定义用户模型,可能有点晚了,因为我们的数据库中有我们不想丢失的数据(一些CMS页面等)。
After we switched AUTH_USER_MODEL to our custom model, we had a lot of problems that we hadn't anticipated, because a lot of other tables had foreign keys to the old auth_user
table, which wasn't deleted. So although things appeared to work on the surface, a lot of things broke underneath: publishing pages, adding images to pages, adding users, etc. because they tried to create an entry in a table that still had a foreign key to auth_user
, without actually inserting a matching record into auth_user
.
在我们将AUTH_USER_MODEL切换到自定义模型之后,我们遇到了很多我们没有预料到的问题,因为很多其他表都有对老的auth_user表的外键,而这个表并没有被删除。因此,尽管表面上似乎有一些工作,但很多东西都崩溃了:发布页面、向页面添加图片、添加用户等等,因为他们试图在一个表中创建一个条目,这个表仍然有一个auth_user的外键,而实际上并没有将一个匹配的记录插入auth_user。
We found a quick and dirty way to rebuild all the tables and relations, and copy our old data across (except for users):
我们找到了一种快速而肮脏的方法来重新构建所有的表和关系,并跨(除了用户)复制我们的旧数据:
- do a full backup of your database with
mysqldump
- 使用mysqldump对数据库进行完整备份吗
- do another backup with no
CREATE TABLE
statements, and excluding a few tables that won't exist after the rebuild, or will be populated bysyncdb --migrate
on a fresh database:south_migrationhistory
- south_migrationhistory
auth_user
- auth_user
auth_user_groups
- auth_user_groups
auth_user_user_permissions
- auth_user_user_permissions
auth_permission
- auth_permission
django_content_types
- django_content_types
django_site
- django_site
- any other tables that belong to apps that you removed from your project (you might only find this out by experimenting)
- 任何属于您从项目中删除的应用程序的其他表(您可能只有通过实验才能发现这一点)
- 做一个备份,没有CREATE TABLE语句,不包括几个表不存在重建后,或将填充syncdb——在一个新的数据库迁移:south_migrationhistory auth_user auth_user_groups auth_user_user_permissions auth_permission django_content_types django_site属于应用程序的任何其他表您从项目(你可能只找到这个由试验)
- drop the database
- 删除数据库的
- recreate the database (e.g.
manage.py syncdb --migrate
) - 重新创建数据库(例如管理)。py syncdb——迁移)
- create a dump of the empty database (to make it faster to go round this loop again)
- 创建空数据库的转储(以使再次循环更快)
- attempt to load the data dump that you created above
- 尝试加载上面创建的数据转储
- if it fails to load because of a duplicate primary key or a missing table, then:
- edit the dump with a text editor
- 使用文本编辑器编辑转储
- remove the statements that lock, dump and unlock that table
- 删除锁定、转储和解锁该表的语句。
- reload the empty database dump
- 重新加载空的数据库转储
- try to load the data dump again
- 尝试再次加载数据转储
- repeat until the data dump loads without errors
- 重复,直到数据转储加载时没有错误
- 如果不能负载,因为重复的主键或失踪的表,然后:用一个文本编辑器编辑转储删除语句,锁,转储,解锁表重载空数据库转储再次加载数据转储重复,直到数据转储负载没有错误
The commands that we ran (for MySQL) were:
我们(为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)
#1
47
South is more than able to do this migration for you, but you need to be smart and do it in stages. Here's the step-by-step guide: (This guide presupposed you subclass AbstractUser
, not AbstractBaseUser
)
South能够为您完成这种迁移,但是您需要聪明地分阶段进行迁移。以下是一步一步的指南:(本指南假定您是AbstractUser的子类,而不是AbstractBaseUser)
-
Before making the switch, make sure that south support is enabled in the application that contains your custom user model (for the sake of the guide, we'll call it
accounts
and the modelUser
). At this point you should not yet have a custom user model.在进行切换之前,请确保在包含自定义用户模型的应用程序中启用了south支持(出于对指南的考虑,我们将其称为accounts和model 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.
-
Create a new, blank user migration in the accounts app.
在accounts应用程序中创建一个新的空白用户迁移。
$ ./manage.py schemamigration accounts --empty switch_to_custom_user Created 0002_switch_to_custom_user.py.
-
Create your custom
User
model in theaccounts
app, but make sure it is defined as:在accounts应用程序中创建您的自定义用户模型,但要确保它定义为:
class SiteUser(AbstractUser): pass
-
Fill in the blank migration with the following code.
用以下代码填充空白迁移。
# 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
-
Run the migration
运行迁移
$ ./manage.py migrate accounts - Migrating forwards to 0002_switch_to_custom_user. > accounts:0002_switch_to_custom_user - Loading initial data for accounts.
-
Make any changes to your user model now.
现在对您的用户模型做任何更改。
# settings.py AUTH_USER_MODEL = 'accounts.User' # accounts/models.py class SiteUser(AbstractUser): site = models.ForeignKey(Site, null=True)
-
create and run migrations for this change
创建并运行此更改的迁移
$ ./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.
Honestly, If you already have good knowledge of your setup and already use south, It should be as simple as adding the following migration to your accounts module.
老实说,如果您已经非常了解您的设置并已经使用了south,那么只需将以下迁移添加到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: added rename for auth_user_group table. FKs will auto update to point at the correct table due to db constraints, but M2M fields' table names are generated from the names of the 2 end tables and will need manual updating in this manner.
编辑2/5/13:添加了auth_user_group表的重命名。FKs由于db限制会自动更新到正确的表,但是M2M字段的表名是由两个结束表的名称生成的,需要手动更新。
EDIT 2: Thanks to @Tuttle & @pix0r for the corrections.
编辑2:感谢@Tuttle & @pix0r修正。
#2
15
My incredibly lazy way of doing this:
我非常懒惰的方法是:
-
Create a new model (User), extending AbstractUser. Within new model, in it's Meta, override db_table and set to 'auth_user'.
创建一个新的模型(用户),扩展AbstractUser。在新模型中,在它的Meta中,重写db_table并设置为“auth_user”。
-
Create an initial migration using South.
使用南方创建初始迁移。
-
Migrate, but fake the migration, using
--fake
when running migrate.迁移,但是伪造迁移,使用——在运行迁移时伪造。
-
Add new fields, create migration, run it normally.
添加新字段,创建迁移,正常运行。
This is beyond lazy, but works. You now have a 1.5 compliant User model, which just uses the old table of users. You also have a proper migration history.
这不是懒惰,而是工作。现在您有了一个兼容1.5的用户模型,它只使用旧的用户表。您还有一个合适的迁移历史。
You can fix this later on with manual migrations to rename the table.
稍后您可以通过手动迁移来修复这个问题,以重命名表。
#3
4
I think you've correctly identified that a migration framework like South is the right way to go here. Assuming you're using South, you should be able to use the Data Migrations functionality to port the old users to your new model.
我想你已经正确地认识到,像南方这样的迁移框架是正确的。假设您正在使用South,那么您应该能够使用数据迁移功能将旧用户移植到新模型。
Specifically, I would add a forwards
method to copy all rows in your user table to the new table. Something along the lines of:
具体地说,我将添加一个forward方法,将用户表中的所有行复制到新表中。类似于:
def forwards(self, orm):
for user in orm.User.objects.all():
new_user = SiteUser(<initialize your properties here>)
new_user.save()
You could also use the bulk_create
method to speed things up.
您还可以使用bulk_create方法来加快速度。
#4
4
I got tired of struggling with South so I actually ended up doing this differently and it worked out nicely for my particular situation:
我厌倦了与南方的斗争,所以我最终做了不同的事情,它很适合我的特殊情况:
First, I made it work with ./manage.py dumpdata, fixing up the dump, and then ./manage.py loaddata, which worked. Then I realized I could do basically the same thing with a single, self-contained script that only loads necessary django settings and does the serialization/deserialization directly.
首先,我让它工作。py dumpdata,修复转储,然后。/管理。py loaddata,工作。然后我意识到我可以用一个独立的脚本做同样的事情,这个脚本只加载必要的django设置并直接执行序列化/反序列化。
Self-contained python script
## 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()
With dumpdata/loaddata
I did the following:
我做了以下几点:
1) ./manage.py dumpdata auth.User
1)。/管理。py dumpdata auth.User
2) Script to convert auth.user data to new user. (or just manually search and replace in your favorite text editor or grep) Mine looked something like:
2)转换auth的脚本。向新用户提供用户数据。(或者只是手工搜索和替换您最喜欢的文本编辑器或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 loaddata filename
3)。/管理。py loaddata文件名
4) set AUTH_USER_MODEL
4)设置AUTH_USER_MODEL
*Side Note: One critical part of doing this type of migration, regardless of which technique you use (South, serialization/modification/deserialization, or otherwise) is that as soon as you set AUTH_USER_MODEL to your custom model in the current settings, django cuts you off from auth.User, even if the table still exists.*
*附加说明:进行这种类型迁移的一个关键部分是,只要在当前设置中将AUTH_USER_MODEL设置为自定义模型,django就会切断您与auth的连接。用户,即使该表仍然存在。*。
#5
2
We decided to switch to a custom user model in our Django 1.6/Django-CMS 3 project, perhaps a little bit late because we had data in our database that we didn't want to lose (some CMS pages, etc).
我们决定在Django 1.6/Django-CMS 3项目中切换到自定义用户模型,可能有点晚了,因为我们的数据库中有我们不想丢失的数据(一些CMS页面等)。
After we switched AUTH_USER_MODEL to our custom model, we had a lot of problems that we hadn't anticipated, because a lot of other tables had foreign keys to the old auth_user
table, which wasn't deleted. So although things appeared to work on the surface, a lot of things broke underneath: publishing pages, adding images to pages, adding users, etc. because they tried to create an entry in a table that still had a foreign key to auth_user
, without actually inserting a matching record into auth_user
.
在我们将AUTH_USER_MODEL切换到自定义模型之后,我们遇到了很多我们没有预料到的问题,因为很多其他表都有对老的auth_user表的外键,而这个表并没有被删除。因此,尽管表面上似乎有一些工作,但很多东西都崩溃了:发布页面、向页面添加图片、添加用户等等,因为他们试图在一个表中创建一个条目,这个表仍然有一个auth_user的外键,而实际上并没有将一个匹配的记录插入auth_user。
We found a quick and dirty way to rebuild all the tables and relations, and copy our old data across (except for users):
我们找到了一种快速而肮脏的方法来重新构建所有的表和关系,并跨(除了用户)复制我们的旧数据:
- do a full backup of your database with
mysqldump
- 使用mysqldump对数据库进行完整备份吗
- do another backup with no
CREATE TABLE
statements, and excluding a few tables that won't exist after the rebuild, or will be populated bysyncdb --migrate
on a fresh database:south_migrationhistory
- south_migrationhistory
auth_user
- auth_user
auth_user_groups
- auth_user_groups
auth_user_user_permissions
- auth_user_user_permissions
auth_permission
- auth_permission
django_content_types
- django_content_types
django_site
- django_site
- any other tables that belong to apps that you removed from your project (you might only find this out by experimenting)
- 任何属于您从项目中删除的应用程序的其他表(您可能只有通过实验才能发现这一点)
- 做一个备份,没有CREATE TABLE语句,不包括几个表不存在重建后,或将填充syncdb——在一个新的数据库迁移:south_migrationhistory auth_user auth_user_groups auth_user_user_permissions auth_permission django_content_types django_site属于应用程序的任何其他表您从项目(你可能只找到这个由试验)
- drop the database
- 删除数据库的
- recreate the database (e.g.
manage.py syncdb --migrate
) - 重新创建数据库(例如管理)。py syncdb——迁移)
- create a dump of the empty database (to make it faster to go round this loop again)
- 创建空数据库的转储(以使再次循环更快)
- attempt to load the data dump that you created above
- 尝试加载上面创建的数据转储
- if it fails to load because of a duplicate primary key or a missing table, then:
- edit the dump with a text editor
- 使用文本编辑器编辑转储
- remove the statements that lock, dump and unlock that table
- 删除锁定、转储和解锁该表的语句。
- reload the empty database dump
- 重新加载空的数据库转储
- try to load the data dump again
- 尝试再次加载数据转储
- repeat until the data dump loads without errors
- 重复,直到数据转储加载时没有错误
- 如果不能负载,因为重复的主键或失踪的表,然后:用一个文本编辑器编辑转储删除语句,锁,转储,解锁表重载空数据库转储再次加载数据转储重复,直到数据转储负载没有错误
The commands that we ran (for MySQL) were:
我们(为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)