Подтвердить что ты не робот

Перенос существующих данных auth.User в новую пользовательскую модель Django 1.5?

Я бы предпочел не уничтожать всех пользователей на моем сайте. Но я хочу воспользоваться пользовательской пользовательской моделью Django 1.5. Здесь моя новая модель пользователя:

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

Все работает с моей новой моделью на новой установке (у меня есть другой код, а также хорошая причина для этого - все это не имеет значения здесь). Но если я поместил это на свой сайт и синхронизирую и перенесю, я потеряю всех своих пользователей или, по крайней мере, они будут в другой, оси сирот, чем новая таблица, созданная для моей новой модели.

Я знаком с Югом, но на основе этот пост и некоторые испытания с моей стороны, кажется, что его миграция данных в настоящее время не является подходит для этой конкретной миграции. Поэтому я ищу способ сделать работу South для этого или для некоторой миграции, не связанной с South (raw SQL, dumpdata/loaddata или иначе), которую я могу запустить на каждом из моих серверов (Postgres 9.2), чтобы перенести пользователей как только новая таблица была создана, а старая таблица auth.User все еще находится в базе данных.

4b9b3361

Ответ 1

Юг более чем способен выполнить эту миграцию для вас, но вам нужно быть умным и делать это поэтапно. Здесь пошаговое руководство: (Это руководство предполагает, что вы подклассом 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

EDIT 2/5/13: добавлено переименование таблицы auth_user_group. FKs автоматически обновит, чтобы указать правильную таблицу из-за ограничений db, но имена таблиц полей M2M генерируются из имен двух конечных таблиц и будут нуждаться в ручном обновлении таким образом.

EDIT 2: Спасибо @Tuttle и @pix0r за исправления.

Ответ 2

Мой невероятно ленивый способ сделать это:

  • Создайте новую модель (Пользователь), расширив AbstractUser. В новой модели, в ней Meta, переопределите db_table и установите значение 'auth_user'.

  • Создайте начальную миграцию с помощью юга.

  • Мигрировать, но подделывать перенос, используя --fake при выполнении миграции.

  • Добавить новые поля, создать миграцию, запустить ее в обычном режиме.

Это не лениво, но работает. Теперь у вас есть совместимая с пользователем модель User, которая просто использует старую таблицу пользователей. У вас также есть соответствующая история миграции.

Вы можете исправить это позже с помощью ручных миграций, чтобы переименовать таблицу.

Ответ 3

Я думаю, что вы правильно определили, что миграционная структура, такая как South, - это правильный путь. Предполагая, что вы используете Юг, вы должны использовать "Перенос данных" для переноса старых пользователей в новую модель.

В частности, я бы добавил метод forwards, чтобы скопировать все строки в таблице пользователя в новую таблицу. Что-то вроде:

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

Вы также можете использовать метод bulk_create, чтобы ускорить процесс.

Ответ 4

Мне надоело бороться с Югом, поэтому я на самом деле закончил это по-другому, и это получилось хорошо для моей конкретной ситуации:

Сначала я работал с dumpdata./manage.py, исправлял дамп, а затем работал. /manage.py loaddata. Затем я понял, что могу сделать одно и то же с единственным автономным script, который загружает только необходимые настройки django и непосредственно выполняет сериализацию/десериализацию.

Автономный 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 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()

С dumpdata/loaddata​​h1 >

Я сделал следующее:

1)./manage.py dumpdata auth.User

2) script для преобразования данных auth.user новому пользователю. (или просто вручную искать и заменять в вашем любимом текстовом редакторе или grep) Mine выглядела примерно так:

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 имя_файла

4) установите AUTH_USER_MODEL

* Сторона Примечание. Одна из важнейших составляющих миграции такого типа, независимо от того, какой метод вы используете (юг, сериализация/модификация/десериализация или иное), заключается в том, что как только вы установите AUTH_USER_MODEL на свою пользовательскую модель в текущем настройки, django отключает вас от auth.User, даже если таблица все еще существует. *

Ответ 5

Мы решили перейти на пользовательскую модель в нашем проекте 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)