3

У меня есть модель UserProfile, которая относится к моей модели User с OneToOneField. Я также использую сигнал post_save для автоматического создания UserProfile, когда пользователь создан. Это отлично работает, когда вы создаете пользователя через администратора (где я использую встроенный), когда я получаю сообщение об ошибке с дублирующимся профилем. This answer recommends setting the primary key to be the OneToOneField referring to user.Как написать миграцию, чтобы изменить первичный ключ модели с ManyToManyField

Так что прежде:

class UserProfile(models.Model): 
    user = models.OneToOneField(settings.AUTH_USER_MODEL) 
    # ... 
    subjects = models.ManyToManyField(Subject, null=True, blank=True) 

После

class UserProfile(models.Model): 
    user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key=True) 
    # ... 
    subjects = models.ManyToManyField(Subject, null=True, blank=True) 

Я пытаюсь сделать это с помощью миграции в Django 1.7, но жизнь осложняется тем, что профиль имеет ряд ManyToManyField - поэтому все они относятся к полю id модели UserProfile. С помощью makemigrations создаются миграции для внесения пользователем первичного ключа и удаления старого поля id, но он игнорирует ManyToManyField.

В настоящее время я перехожу к кроличьей норе, используя множество операторов RunSQL в процессе миграции, чтобы изменить сквозной стол для ManyToManyField. Я только что нажал другую ошибку, где имя ограничения не одинаково в одной таблице, как другое.

Итак, мой вопрос: существует ли способ миграции Django, который будет выполнять работу по изменению таблицы сквозных, чтобы он ссылался на новый первичный ключ, обновляя все ограничения, ключи и т. Д.? Если нет, каков наилучший способ справиться с этой ситуацией?

Я использую Django 1.7 с MySQL.

+1

Я бы сказал, что решение неверно. Ваш сигнал должен быть изменен, чтобы не пытаться сортировать повторяющиеся профили.Первичное ключевое решение просто кажется мне взломанным. –

+0

@Kye - обработчик сигнала создает профиль ** до ** admin inline пытается создать профиль. Таким образом, обработчик сигнала должен был бы разработать пользователь, создаваемый администратором, чтобы знать, что администратор попытается создать пользователя - он не может просто проверить, не существует ли профиля в базе данных. Альтернативой было бы иметь встроенный тест администратора, если профиль уже существует до его создания, но это кажется мне взломанным. –

+0

@HamishDowner выглядит как его ошибка: https://code.djangoproject.com/ticket/25012 – Anupam

ответ

2

Итак, я закончил с SQL, чтобы исправить это. Ядро моего решения ниже - в основном я

  • создать индекс на user_id в новом профиле
    • этот показатель должен существовать, прежде чем я могу ссылаться на него в качестве внешнего ключа
  • создать новый через стол
    • Я начал с выходом SHOW CREATE TABLE userprofile_userprofile_subjects (MySQL специфический)
    • Я изменил ключевые имена и имена ограничений слегка
  • скопировать все данные в новом через таблицу
  • падение старого через таблицу
  • переименовать новый через стол, чтобы иметь название старого через таблицу
  • , наконец, делать операции, которые Джанго миграции автоматически сгенерированные для меня

Я надеюсь, что это поможет кому-то еще. И мне все равно интересно узнать о лучшем решении.

from django.db import migrations 

class Migration(migrations.Migration): 

    dependencies = [ 
     # ... 
    ] 

    operations = [ 
     migrations.RunSQL(
      'ALTER TABLE userprofile_userprofile ' 
      'ADD INDEX `userprofile_userprofile_1234abcd` (user_id)' 
     ), 
     migrations.RunSQL (
      'CREATE TABLE userprofile_temp_table (' 
      '`id` int(11) NOT NULL AUTO_INCREMENT, ' 
      '`userprofile_id` int(11) NOT NULL, ' 
      '`subject_id` int(11) NOT NULL, ' 
      'PRIMARY KEY (`id`), ' 
      'UNIQUE KEY `userprofile_userprofile_subjects_userprofile_us_7ded3060_uniq` (`userprofile_id`,`subject_id`), ' 
      'KEY `userprofile_userprofile_subject_1be9924f` (`userprofile_id`), ' 
      'KEY `userprofile_userprofile_subject_e5a9504a` (`subject_id`), ' 
      'CONSTRAINT `subject_id_refs_id_69796996` FOREIGN KEY (`subject_id`) REFERENCES `otherapp_subject` (`id`), ' 
      'CONSTRAINT `userprofile_user_id_refs_user_id_1234abcd` FOREIGN KEY (`userprofile_id`) REFERENCES `userprofile_userprofile` (`user_id`) ' 
      ') ENGINE=InnoDB AUTO_INCREMENT=35500 DEFAULT CHARSET=utf8 ' 
     ), 
     migrations.RunSQL (
      'INSERT INTO userprofile_temp_table ' 
      '(userprofile_id, subject_id) ' 
      '(' 
      ' SELECT userprofile_userprofile.user_id, userprofile_userprofile_subjects.subject_id' 
      ' FROM userprofile_userprofile_subjects' 
      ' INNER JOIN userprofile_userprofile' 
      ' ON userprofile_userprofile_subjects.userprofile_id =' 
      '  userprofile_userprofile.id' 
      ')' 
     ), 
     migrations.RunSQL (
      'DROP TABLE `userprofile_userprofile_subjects`' 
     ), 
     migrations.RunSQL (
      'RENAME TABLE `userprofile_temp_table` TO `userprofile_userprofile_subjects`' 
     ), 
     migrations.RemoveField(
      model_name='userprofile', 
      name='id', 
     ), 
     migrations.AlterField(
      model_name='userprofile', 
      name='user', 
      field=models.OneToOneField(
       primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL 
      ), 
      preserve_default=True, 
     ), 
    ] 
+1

Спасибо @Hamish - ваше решение помогло мне решить не использовать настраиваемый первичный ключ с моделями с областями m2m :) Столкнулся с несколькими ошибками на Django с этим ([# 25012] (https://code.djangoproject.com/ticket/25012), [# 24030] (https://code.djangoproject.com/ticket/24030), [# 22997] (https://code.djangoproject.com/ticket/22997)). Подробности [здесь] (http://stackoverflow.com/questions/43253602/django-short-non-linear-non-predictable-id-in-the-url). – Anupam

 Смежные вопросы

  • Нет связанных вопросов^_^