Добавить "сквозную" таблицу в поле django и мигрировать с юга? - PullRequest
13 голосов
/ 19 мая 2011

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

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

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 в Meta? Разве я просто не использую through=... сразу ... затем сделаю schemamigration --auto, затем datamigration, чтобы скопировать текущую таблицу (каким-то образом, не уверен ...), а затем добавлю отношение through и это убить стол?

В чем тут подвох? Это действительно так сложно?

Ответы [ 3 ]

14 голосов
/ 19 мая 2011

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

Прежде всего, убедитесь, что создаваемая вручную таблица с таблицей имеет то же имя таблицы в базе данных, что и 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')

Это должно дать вам то, что вы ищете.

5 голосов
/ 17 февраля 2016

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

  1. Создать новый класс модели, который точно соответствует встроенной сквозной таблице
  2. Используйте класс Meta, чтобы установить имя таблицы в соответствии с существующей таблицей
  3. Создайте миграцию, которая создаст новую таблицу и установит ее в качестве сквозной для поля.
  4. Не запуская эту миграцию, отредактируйте ее, чтобы обернуть в миграцию migrations. SeparateDatabaseAndState, где автоматически сгенерированные шаги находятся в поле state_operations, а операции с базой данных пусты.
  5. При необходимости измените свою сквозную таблицу, убедившись, что генерируйте новые миграции как обычно.
0 голосов
/ 05 ноября 2015

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

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

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

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

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') 

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

...