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

Добавление таблицы "через" в поле django и миграция с помощью South?

Кажется, что это должно быть "легким" или, по крайней мере, документированным где-то, я просто не могу его найти.

Допустим, у меня есть модель:

class A(models.Model):
    users = models.ManyToMany('auth.User', blank=True)

Теперь я хочу перейти на таблицу through, чтобы добавить поля в отношение ManyToMany...

class AUsers(models.Model):
    user = models.ForeignKey('auth.User')
    a = models.ForeignKey('A')
    new_field = models.BooleanField()

class A(models.Model):
    users = models.ManyToMany('auth.User', blank=True, through='AUsers')

Тогда я делаю:

% ./manage.py schemamigration app --auto

Не совсем удивительно, он говорит мне, что он собирается отказаться от оригинальной автоматической сборки через таблицу и создать новую для AUsers. Какая лучшая практика на данный момент? Есть ли достойный способ перехода на новую таблицу through? Использовать ли db_table в мета? Я просто не использую through=... сразу... затем выполните schemamigration --auto, затем datamigration, чтобы скопировать текущую таблицу (как-то, не уверен...), а затем добавить отношение through и позволить он убивает таблицу?

Какой трюк здесь? Это действительно так сложно?

4b9b3361

Ответ 1

Вы можете сделать это довольно легко.

Прежде всего, убедитесь, что руководство с помощью таблицы, которую вы создаете, имеет одно и то же имя таблицы в базе данных, которое было создано изначально созданного Django.

Итак, во-первых, рассмотрим руководство через модель до вашего изменения:

class AUsers(models.Model):
    user = models.ForeignKey('auth.User')
    a = models.ForeignKey('A')

    class Meta:
        db_table = 'appname_a_user'

Это должно быть функционально (почти) идентично ManyToManyField, которое вы использовали. Фактически, вы могли выполнить пустую миграцию и применить ее, а затем использовать --auto для своих изменений (но не).

Теперь добавьте свое поле, как вы делали в приведенном выше примере кода, а затем запустите ./manage.py schemamigration appname manual_through_table --empty. Это даст вам пустую миграцию с именем ####_manual_through_table.py.

В самой миграции будет использоваться метод forwards и backwards. Каждая из них должна быть по одной строке:

def forwards(self, orm):
    db.add_column('appname_a_user', 'new_field', self.gf('django.db.models.fields.BooleanField')(default=False))

def backwards(self, orm):
    db.delete_column('appname_a_user', 'new_field')

Это должно сделать то, что вам нужно.

Ответ 2

Если кто-то сталкивается с этим вопросом при попытке сделать то же самое с инфраструктурой переноса современных, вот шаги:

  • Создайте новый класс модели, который точно соответствует встроенной таблице.
  • Используйте класс Meta для установки имени таблицы в соответствии с существующей таблицей
  • Сгенерируйте миграцию, которая создаст новую таблицу и установит ее как сквозную для поля.
  • Не запуская эту миграцию, отредактируйте ее, чтобы обернуть ее в миграции migrations. SeparateDatabaseAndState, где автоматически сгенерированные шаги находятся в поле state_operations, а операции с базой данных пусты.
  • Измените свою таблицу, если необходимо, чтобы генерировать новые миграции как обычно.

Ответ 3

Как уже упоминалось в комментарии, первый шаг можно упростить, используя db.rename_table, как описано здесь, который дает это через модель:

class AUsers(models.Model):
user = models.ForeignKey('auth.User')
a = models.ForeignKey('A')

class Meta:
    unique_together = (('user', 'a'),)

Затем создайте миграцию с помощью --auto (таким образом, вы увидите имена таблиц DB) и замените содержимое на:

class Migration(SchemaMigration):

    def forwards(self, orm):
        db.rename_table('appname_a_user', 'appname_auser')

    def backwards(self, orm):
        db.rename_table('appname_auser','appname_a_user') 

Я просто применил его в своем проекте без проблем.