Могу ли я объединить миграцию схемы и данных (Юг) в одну? - PullRequest
14 голосов
/ 06 января 2012

Я хочу переместить поле honk и данные из одной модели в другую, используя Юг:

class Foo(models.Model):
    foofield = models.CharField()
    honk = models.PositiveIntegerField()

class Bar(models.Model):
    barfield = models.CharField()

Я делал это раньше, используя 3 отдельные миграции:

  1. Миграция схемы, добавление honk к Bar
  2. Миграция данных, копирование всех Foo.honk данных в Bar.honk
  3. Другая миграция схемы, отбрасывание honk из Foo

Можно ли выполнить эти три шагаза одну миграцию?

Я уже узнал, что нет большой разницы между миграцией схемы и данных на юге , поэтому я подумал, что, возможно, что-то подобное может сработать (чтотри вышеперечисленные миграции просто объединены в одну):

class Migration(DataMigration):
    def forwards(self, orm):
        # add column
        db.add_column('myapp_bar', 'honk', self.gf('django.db.models.fields.PositiveIntegerField')(default='0'), keep_default=False)

        # copy data
        for foo in Foo.objects.all():
            # find the right bar here and then ...
            bar.honk = foo.honk
            bar.save()

        # remove old column
        db.delete_column('myapp_foo', 'honk')

Будет ли это работать или не получится, потому что мой (на юге замороженный) orm еще не знает о Bar.honk?Или я делаю это неправильно, и есть более хороший способ сделать это за одну миграцию?

Ответы [ 4 ]

15 голосов
/ 19 января 2012

Так как этот вопрос принес мне значок Tumbleweed , я закопался и попробовал сам. Вот что я узнал.

Нет, вы не можете объединить эти миграции

Поскольку замораживание ORM содержит только схему, на которую вы выполняете миграцию. Таким образом, в приведенном выше примере foo.honk не будет доступен во время переноса данных (цикл для ), поскольку он удаляется во время переноса схемы, поэтому он не в замороженном ОРМ. Кроме того, вы получите исключения DatabaseError, если попытаетесь получить доступ к данным, поскольку столбцы в базе данных еще не соответствуют столбцам модели (т. Е. Если вы попытаетесь получить доступ к чему-либо до db.add_column ).

Похоже, что нет простого ярлыка, и для выполнения чего-то подобного требуется три миграции, упомянутые выше.

1 голос
/ 08 февраля 2013

С этой точки зрения документации не хватает, но если вы измените замерзшую часть ORM в миграции, добавив себе пропущенное поле, тогда оно будет доступно: я имею в виду, что во время миграции на юг вы должны использоватьзаблокированный ORM , поскольку в будущем вы будете мигрировать, модель Foo может потерять поле honk.

Я думаю, что если вы измените заблокированное объявление ORM, как показано ниже

models = {
    'app.foo': {
        'Meta': {'object_name': 'Foo'},
        'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
        'foofield': ('django.db.models.fields.CharField', [],{'max_length':666}),
        'honk': ('django.db.models.fields.PositiveIntegerField', [], {}),
    },
    'app.bar': {
        'Meta': {'object_name': 'Bar'},
        'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
        'barfield': ('django.db.models.fields.CharField', [],{'max_length':666}),
        'honk': ('django.db.models.fields.PositiveIntegerField', [], {}),
    },
}

complete_apps = ['app']
symmetrical = True

все будет работать:)

Хитрость заключается в определении поля honk в каждой модели, очевидно, должен присутствовать столбец в базе данных

class Migration(DataMigration):
    def forwards(self, orm):
        # add column
        db.add_column('myapp_bar', 'honk', self.gf('django.db.models.fields.PositiveIntegerField')(default='0'), keep_default=False)

        # copy data
        for foo in Foo.objects.all():
            # find the right bar here
            bar = orm.Bar.objects.get(**whatever)
            bar.honk = foo.honk
            bar.save()

        # remove old column
        db.delete_column('myapp_foo', 'honk')

PS: как указано @ acjohnson55 symmetrical = True действительно важно

0 голосов
/ 24 февраля 2014

Как отметил Ингмар, южный ORM зависает в определенный момент времени, что не позволяет вам получить доступ к столбцам, о которых ORM не знает. Тем не менее, на самом деле есть способ обойти это: вам не нужно использовать ORM или вообще никакого ORM; вместо этого вы можете выполнять необработанные SQL-запросы

Так, например, вместо

for foo in Foo.objects.all():
    print foo.honk

вы можете сделать что-то вроде:

cursor.execute('SELECT "honk" FROM "myapp_foo"')
for honk, in cursor.fetchall():
    print honk
0 голосов
/ 28 сентября 2012

это работает для меня:

def migratedata(orm):
   # copy data, need to lookup model through orm.
   for foo in orm['myapp.foo'].objects.all():
      # find the right bar here and then ...
      bar.honk = foo.honk
      bar.save()

class Migration(SchemaMigration):
   def forwards(self, orm):
      # add column
      db.add_column('myapp_bar', 'honk', self.gf('django.db.models.fields.PositiveIntegerField')(default='0'), keep_default=False)
      # migrate data
      if not db.dry_run:
         migratedata(orm)
      # remove old column
      db.delete_column('myapp_foo', 'honk')

Однако я не рекомендую это, потому что это легко испортить.Особое внимание необходимо уделить уникальности и порядку операций (IOW, не переносите данные после того, как вы удалили соответствующие поля (:)

...