Como mover um modelo entre dois aplicativos Django (Django 1.7)


133

Então, há cerca de um ano, iniciei um projeto e, como todos os novos desenvolvedores, não me concentrei muito na estrutura, no entanto, agora que estou mais junto com o Django, começou a parecer que o layout do meu projeto, principalmente meus modelos, são horríveis na estrutura .

Eu tenho modelos mantidos principalmente em um único aplicativo e, na verdade, a maioria desses modelos deve estar em seus próprios aplicativos individuais. Tentei resolver isso e movê-los para o sul. No entanto, achei complicado e muito difícil devido às chaves estrangeiras ect.

No entanto, devido ao Django 1.7 e suporte embutido para migrações, existe uma maneira melhor de fazer isso agora?


4
Você pode considerar alterar a resposta aceita.
precisa saber é o seguinte

Para as pessoas que se depararem com isso no futuro: Django 3.x aqui, e a abordagem detalhada em realpython.com/move-django-model/… funcionou para mim. Eu tinha várias chaves estrangeiras entre modelos no aplicativo antigo e modelos no novo aplicativo.
pradeepcep 18/06

Respostas:


16

Estou removendo a resposta antiga, pois pode resultar em perda de dados. Como o ozan mencionou , podemos criar duas migrações, uma em cada aplicativo. Os comentários abaixo deste post se referem à minha resposta antiga.

Primeira migração para remover o modelo do 1º aplicativo.

$ python manage.py makemigrations old_app --empty

Edite o arquivo de migração para incluir essas operações.

class Migration(migrations.Migration):

    database_operations = [migrations.AlterModelTable('TheModel', 'newapp_themodel')]

    state_operations = [migrations.DeleteModel('TheModel')]

    operations = [
      migrations.SeparateDatabaseAndState(
        database_operations=database_operations,
        state_operations=state_operations)
    ]

Segunda migração, que depende da primeira migração e cria a nova tabela no 2º aplicativo. Depois de mover o código do modelo para o segundo aplicativo

$ python manage.py makemigrations new_app 

e edite o arquivo de migração para algo assim.

class Migration(migrations.Migration):

    dependencies = [
        ('old_app', 'above_migration')
    ]

    state_operations = [
        migrations.CreateModel(
            name='TheModel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ],
            options={
                'db_table': 'newapp_themodel',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]

Eu tenho dados existentes e muitos deles que simplesmente não posso perder, é possível fazê-lo com isso?
Sam Buckingham

@KevinChristopherHenry Modificou o código. Isso preserva os dados existentes.
precisa saber é o seguinte

@SamBuckingham Sim, você pode tentar com o código modificado migrar sem perder os dados.
precisa saber é o seguinte

2
Eu acho que essa será a melhor maneira, obrigado por toda a ajuda pessoal que tem sido brilhante.
Sam Buckingham

1
Na IMO, essa é uma solução errada, a suposição básica de migração é que, se você executar, ./manage.py migratetudo terminará em bom estado. Falsificar migrações manualmente é uma maneira incorreta da IMO.
jb.

341

Isso pode ser feito com bastante facilidade usando migrations.SeparateDatabaseAndState. Basicamente, usamos uma operação de banco de dados para renomear a tabela simultaneamente com duas operações de estado para remover o modelo do histórico de um aplicativo e criá-lo no outro.

Remover do aplicativo antigo

python manage.py makemigrations old_app --empty

Na migração:

class Migration(migrations.Migration):

    dependencies = []

    database_operations = [
        migrations.AlterModelTable('TheModel', 'newapp_themodel')
    ]

    state_operations = [
        migrations.DeleteModel('TheModel')
    ]

    operations = [
        migrations.SeparateDatabaseAndState(
            database_operations=database_operations,
            state_operations=state_operations)
    ]

Adicionar à nova aplicação

Primeiro, copie o modelo para o novo model.py do aplicativo, depois:

python manage.py makemigrations new_app

Isso gerará uma migração com uma CreateModeloperação ingênua como a única operação. Embrulhe isso em uma SeparateDatabaseAndStateoperação para que não tentemos recriar a tabela. Inclua também a migração anterior como uma dependência:

class Migration(migrations.Migration):

    dependencies = [
        ('old_app', 'above_migration')
    ]

    state_operations = [
        migrations.CreateModel(
            name='TheModel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ],
            options={
                'db_table': 'newapp_themodel',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]

14
Realmente boa explicação. Essa deve ser a resposta, ao renomear a tabela, você evita a perda de dados.
Remiz 23/10

11
Esta é a melhor maneira de fazê-lo e é muito melhor que a minha. Nota adicionada no topo da minha resposta.
ChillarAnand

4
Fiz isso, mas quando executo "makemigrations" no newapp depois disso, ele gera uma migração AlterModelTable renomeando-a para None.
Diego Ponciano

4
Encontrei uma maneira de resolver meu problema com base nessas instruções. O problema é mais complicado se você tiver referências de chave estrangeira que são campos obrigatórios. Eu tive que adicionar alguns passos para mover as referências.
Nostalg.io

14
Devido a várias solicitações, criei uma resposta detalhada sobre migrações de modelos FK com um exemplo do GitHub. stackoverflow.com/questions/30601107/…
Nostalg.io

26

Eu encontrei o mesmo problema. A resposta de Ozan me ajudou muito, mas infelizmente não foi suficiente. Na verdade, eu tinha várias ForeignKey vinculadas ao modelo que eu queria mover. Após algumas dores de cabeça, encontrei a solução e resolvi publicá-la para resolver o tempo das pessoas.

Você precisa de mais 2 etapas:

  1. Antes de fazer qualquer coisa, mudar toda a sua ForeignKeyligação a TheModelem Integerfield. Então corrapython manage.py makemigrations
  2. Depois de seguir os passos de Ozan, converta novamente suas chaves estrangeiras: adie ForeignKey(TheModel) vez de IntegerField(). Em seguida, faça as migrações novamente ( python manage.py makemigrations). Em seguida, você pode migrar e deve funcionar ( python manage.py migrate)

Espero que ajude. Claro que testá-lo no local antes de tentar na produção para evitar surpresas ruins :)


8
e os relacionamentos ManyToManyField ??
precisa saber é o seguinte

1
@tomcounsell ótimo comentário, eu diria que adicionando um modelo específico apenas para fins de migração. Grande quantidade de trabalho necessário para deixar os dados intactos ...
Wtower

Como um relacionamento muitos para muitos geralmente é apenas uma tabela com duas chaves estrangeiras, do ponto de vista do SQL, você pode aplicar o truque desta resposta. Mas, para conseguir isso apenas via Django, uma abordagem que eu possa pensar seria na linha de resposta @ozan, exceto que o primeiro passo seria duplicar as tabelas envolvidas no relacionamento MTM (uma versão dos enganados em cada aplicativo) , migre todas as Chaves estrangeiras para o novo aplicativo e exclua somente os dupes no aplicativo antigo. Disclaimer: Eu não testei :)
Arnaud P

15

Como eu fiz isso (testado no Django == 1.8, com postgres, provavelmente também 1.7)

Situação

app1.YourModel

mas você deseja que ele vá para: app2.YourModel

  1. Copie YourModel (o código) do app1 para o app2.
  2. adicione isso ao app2.YourModel:

    Class Meta:
        db_table = 'app1_yourmodel'
  3. $ python manage.py makemigrations app2

  4. Uma nova migração (por exemplo, 0009_auto_something.py) é feita no app2 com uma instrução migrations.CreateModel (), mova essa instrução para a migração inicial do app2 (por exemplo, 0001_initial.py) (será como sempre esteve lá). E agora remova a migração criada = 0009_auto_something.py

  5. Assim como você age, como o app2.YourModel sempre esteve lá, agora remova a existência do app1.YourModel das suas migrações. Significado: comente as instruções CreateModel e todos os ajustes ou migração de dados que você usou depois disso.

  6. E, é claro, todas as referências ao app1.YourModel precisam ser alteradas para app2.YourModel através do seu projeto. Além disso, não esqueça que todas as chaves estrangeiras possíveis para app1.YourModel nas migrações devem ser alteradas para app2.YourModel

  7. Agora, se você migrar o $ python manage.py, nada mudou, também quando você fizer as migrações do $ python manage.py, nada de novo foi detectado.

  8. Agora, o toque final: remova o Class Meta de app2.YourModel e faça $ python manage.py makemigrations app2 && python manage.py migrate app2 (se você olhar para essa migração, verá algo assim :)

        migrations.AlterModelTable(
        name='yourmodel',
        table=None,
    ),

table = None, significa que ele assumirá o nome da tabela padrão, que neste caso será app2_yourmodel.

  1. FEITO, com os dados salvos.

PS durante a migração, verá que esse content_type app1.yourmodel foi removido e pode ser excluído. Você pode dizer sim a isso, mas apenas se não o usar. Caso você dependa muito dele para que os FKs desse tipo de conteúdo estejam intactos, ainda não responda sim ou não, mas vá para o banco de dados nesse momento manualmente e remova o tipo de conteúdo app2.yourmodel e renomeie o contenttype app1. yourmodel para app2.yourmodel e continue respondendo não.


3
Embora esta solução seja definitivamente "mais hackeada" do que a @ ozan e definitivamente precise de mais edição, funcionou muito bem para mim (e não há problema em editar migrações - elas devem ser editáveis, de acordo com os documentos).
Pgcd

1
Possivelmente também use a app_label = 'app1'opção meta.
Wtower

Gênio! Isso funcionou muito bem para mim nos relacionamentos com ForeignKey. Suponho que isso também funcione para os campos ManyToMany.
Babken Vardanyan

Segui suas etapas, mas o campo em algum modelo pertencente ao app1 consiste em uma Chave estrangeira com um relacionamento recursivo com o modelo (myModel) a ser movido. Como field1 = models.ForeignKey('app1.myModel').Quando eu migrar, eu recebo uma ValueError afirmando quefield1 was declared with a lazy reference to 'app1.myModel' but app 'app1' doesn't provide model 'MyModel'
Deesha

12

Recebo migrações nervosas de codificação manual (conforme exigido pela resposta de Ozan ), de modo que o seguinte combina as estratégias de Ozan e Michael para minimizar a quantidade de codificação manual necessária:

  1. Antes de mover qualquer modelo, verifique se você está trabalhando com uma linha de base limpa executando makemigrations.
  2. Mova o código do modelo de app1paraapp2
  3. Conforme recomendado por @Michael, apontamos o novo modelo para a tabela antiga do banco de dados usando a db_tableopção Meta no modelo "novo":

    class Meta:
        db_table = 'app1_yourmodel'
  4. Corra makemigrations. Isso irá gerar CreateModeldentro app2e DeleteModeldentro app1. Tecnicamente, essas migrações se referem exatamente à mesma tabela e removeriam (incluindo todos os dados) e recriariam a tabela.

  5. Na realidade, não queremos (ou precisamos) fazer nada com a mesa. Nós apenas precisamos do Django acreditar que a mudança foi feita. Pela resposta de @ Ozan, a state_operationsbandeira SeparateDatabaseAndStatefaz isso. Então, nós envolvemos todas as migrationsentradas NOS DOIS MIGRAÇÕES FILES com SeparateDatabaseAndState(state_operations=[...]). Por exemplo,

    operations = [
        ...
        migrations.DeleteModel(
            name='YourModel',
        ),
        ...
    ]

    torna-se

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=[
            ...
            migrations.DeleteModel(
                name='YourModel',
            ),
            ...
        ])
    ]
  6. Você também precisa garantir que a nova CreateModelmigração "virtual" dependa de qualquer migração que realmente tenha criado ou alterado a tabela original . Por exemplo, se suas novas migrações são app2.migrations.0004_auto_<date>(para Create) e app1.migrations.0007_auto_<date>(para Delete), a coisa mais simples a fazer é:

    • Abra app1.migrations.0007_auto_<date>e copie sua app1dependência (por exemplo ('app1', '0006...'),). Essa é a migração "imediatamente anterior" app1e deve incluir dependências em toda a lógica de criação de modelo real.
    • Abra app2.migrations.0004_auto_<date>e adicione a dependência que você acabou de copiar em sua dependencieslista.

Se você tem um ForeignKeyrelacionamento com o modelo que está movendo, o que foi dito acima pode não funcionar. Isso acontece porque:

  • Dependências não são criadas automaticamente para as ForeignKeyalterações
  • Como não queremos agrupar as ForeignKeyalterações state_operations, precisamos garantir que elas sejam separadas das operações da tabela.

NOTA: O Django 2.2 adicionou um aviso ( models.E028) que quebra esse método. Você pode contornar isso, managed=Falsemas eu não o testei.

O conjunto "mínimo" de operações difere dependendo da situação, mas o procedimento a seguir deve funcionar para a maioria / todas as ForeignKeymigrações:

  1. COPIE o modelo de app1para app2, defina db_table, mas NÃO altere nenhuma referência FK.
  2. Execute makemigrationse agrupe toda a app2migração state_operations(veja acima)
    • Como acima, adicione uma dependência na app2 CreateTableúltima app1migração
  3. Aponte todas as referências FK para o novo modelo. Se você não estiver usando referências de seqüência de caracteres, mova o modelo antigo para a parte inferior de models.py(NÃO remova-o) para que ele não concorra com a classe importada.
  4. Execute, makemigrationsmas NÃO envolva nada state_operations(as alterações do FK realmente devem acontecer). Adicione uma dependência em todas as ForeignKeymigrações (ou seja AlterField) à CreateTablemigração app2(você precisará desta lista para a próxima etapa, portanto, acompanhe-as). Por exemplo:

    • Encontre a migração que inclui, CreateModelpor exemplo, app2.migrations.0002_auto_<date>e copie o nome dessa migração.
    • Encontre todas as migrações que tenham uma ForeignKey para esse modelo (por exemplo, pesquisando app2.YourModelpara encontrar migrações como:

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
          ]
      
          operations = [
              migrations.AlterField(
                  model_name='relatedmodel',
                  name='fieldname',
                  field=models.ForeignKey(... to='app2.YourModel'),
              ),
          ]
    • Adicione a CreateModelmigração como uma dependência:

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
              ('app2', '0002_auto_<date>'),
          ]  
  5. Remova os modelos de app1

  6. Corre makemigrations e agrupe a app1migração state_operations.
    • Adicione uma dependência a todas as ForeignKeymigrações (ou seja,AlterField ) da etapa anterior (pode incluir migrações em app1e app2).
    • Quando eu criei essas migrações, elas DeleteTablejá dependiam das AlterFieldmigrações, então não precisei aplicá-las manualmente (ou seja, Alterantes Delete).

Neste ponto, o Django está pronto. O novo modelo aponta para a tabela antiga e as migrações do Django convenceram-na de que tudo foi realocado adequadamente. A grande ressalva (da resposta de @ Michael) é que um novoContentType é criado para o novo modelo. Se você vincular (por exemplo, por ForeignKey) a tipos de conteúdo, precisará criar uma migração para atualizar a ContentTypetabela.

Eu queria limpar depois de mim mesmo (opções Meta e nomes de tabelas), então usei o seguinte procedimento (do @Michael):

  1. Remova o db_table entrada Meta
  2. Corre makemigrations novamente para gerar a renomeação do banco de dados
  3. Edite essa última migração e verifique se depende da DeleteTablemigração. Não parece que seja necessário, pois Deletedeve ser puramente lógico, mas cometer erros (por exemplo app1_yourmodel, não existe) se não existir.

Isso funcionou perfeitamente, obrigado! Eu não acho que a edição da última migração seja importante, pois ela está na parte inferior da árvore de dependência.
James Meakin

1
Boa resposta! Eu acho que você precisa adicionar um parêntese de fechamento para migrations.SeparateDatabaseAndState, certo?
Atm

Isso funcionou para mim. Também não editei a última migração (etapa 3, a última linha de toda a resposta) como @ JamesMeakin e ainda funcionou bem.
Megawatt

no segundo cenário, aquele com FKs, o segundo passo falhou para mim com um erro que faz sentido:table_name: (models.E028) db_table 'table_name' is used by multiple models: app1.Model, app2.Model.
Mihai Zamfir

Eu usei o procedimento algumas vezes. Se você comparar a documentação para 2.2 ( docs.djangoproject.com/en/2.2/ref/checks ) e 2.1 ( docs.djangoproject.com/en/2.1/ref/checks ), poderá ver que ela foi adicionada no 2.2. Pode ser possível contornar, managed=Falsemas não estou em lugar para verificar.
claytond 16/03

1

Outra alternativa hacky, se os dados não forem grandes ou muito complicados, mas ainda importantes de manter, é:

  • Obter acessórios de dados usando manage.py dumpdata
  • Prossiga para modelar mudanças e migrações corretamente, sem relacionar as mudanças
  • Global substitua os equipamentos dos nomes antigos de modelo e aplicativo pelos novos
  • Carregar dados usando manage.py loaddata

1

Copiado da minha resposta em https://stackoverflow.com/a/47392970/8971048

Caso você precise mover o modelo e não tenha mais acesso ao aplicativo (ou não queira mais), crie uma nova Operação e considere criar um novo modelo apenas se o modelo migrado não existir.

Neste exemplo, estou passando 'MyModel' de old_app para myapp.

class MigrateOrCreateTable(migrations.CreateModel):
    def __init__(self, source_table, dst_table, *args, **kwargs):
        super(MigrateOrCreateTable, self).__init__(*args, **kwargs)
        self.source_table = source_table
        self.dst_table = dst_table

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        table_exists = self.source_table in schema_editor.connection.introspection.table_names()
        if table_exists:
            with schema_editor.connection.cursor() as cursor:
                cursor.execute("RENAME TABLE {} TO {};".format(self.source_table, self.dst_table))
        else:
            return super(MigrateOrCreateTable, self).database_forwards(app_label, schema_editor, from_state, to_state)


class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0002_some_migration'),
    ]

    operations = [
        MigrateOrCreateTable(
            source_table='old_app_mymodel',
            dst_table='myapp_mymodel',
            name='MyModel',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=18))
            ],
        ),
    ]

Não adicione a mesma resposta a várias perguntas. Responda à melhor e marque o restante como duplicado. Consulte É aceitável adicionar uma resposta duplicada a várias perguntas?
usar o seguinte

0

Isso é testado aproximadamente, portanto, não esqueça de fazer backup do seu banco de dados !!!

Por exemplo, existem dois aplicativos: src_appe dst_appqueremos mover o modelo MoveMede src_appparadst_app .

Crie migrações vazias para os dois aplicativos:

python manage.py makemigrations --empty src_app
python manage.py makemigrations --empty dst_app

Vamos supor que as novas migrações são XXX1_src_app_newe XXX1_dst_app_new, as principais migrações anteriores são XXX0_src_app_oldeXXX0_dst_app_old .

Adicione uma operação que renomeie a tabela para o MoveMemodelo e renomeie seu app_label no ProjectState para XXX1_dst_app_new. Não se esqueça de adicionar dependência à XXX0_src_app_oldmigração. A XXX1_dst_app_newmigração resultante é:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

# this operations is almost the same as RenameModel
# https://github.com/django/django/blob/1.7/django/db/migrations/operations/models.py#L104
class MoveModelFromOtherApp(migrations.operations.base.Operation):

    def __init__(self, name, old_app_label):
        self.name = name
        self.old_app_label = old_app_label

    def state_forwards(self, app_label, state):

        # Get all of the related objects we need to repoint
        apps = state.render(skip_cache=True)
        model = apps.get_model(self.old_app_label, self.name)
        related_objects = model._meta.get_all_related_objects()
        related_m2m_objects = model._meta.get_all_related_many_to_many_objects()
        # Rename the model
        state.models[app_label, self.name.lower()] = state.models.pop(
            (self.old_app_label, self.name.lower())
        )
        state.models[app_label, self.name.lower()].app_label = app_label
        for model_state in state.models.values():
            try:
                i = model_state.bases.index("%s.%s" % (self.old_app_label, self.name.lower()))
                model_state.bases = model_state.bases[:i] + ("%s.%s" % (app_label, self.name.lower()),) + model_state.bases[i+1:]
            except ValueError:
                pass
        # Repoint the FKs and M2Ms pointing to us
        for related_object in (related_objects + related_m2m_objects):
            # Use the new related key for self referential related objects.
            if related_object.model == model:
                related_key = (app_label, self.name.lower())
            else:
                related_key = (
                    related_object.model._meta.app_label,
                    related_object.model._meta.object_name.lower(),
                )
            new_fields = []
            for name, field in state.models[related_key].fields:
                if name == related_object.field.name:
                    field = field.clone()
                    field.rel.to = "%s.%s" % (app_label, self.name)
                new_fields.append((name, field))
            state.models[related_key].fields = new_fields

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        old_apps = from_state.render()
        new_apps = to_state.render()
        old_model = old_apps.get_model(self.old_app_label, self.name)
        new_model = new_apps.get_model(app_label, self.name)
        if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
            # Move the main table
            schema_editor.alter_db_table(
                new_model,
                old_model._meta.db_table,
                new_model._meta.db_table,
            )
            # Alter the fields pointing to us
            related_objects = old_model._meta.get_all_related_objects()
            related_m2m_objects = old_model._meta.get_all_related_many_to_many_objects()
            for related_object in (related_objects + related_m2m_objects):
                if related_object.model == old_model:
                    model = new_model
                    related_key = (app_label, self.name.lower())
                else:
                    model = related_object.model
                    related_key = (
                        related_object.model._meta.app_label,
                        related_object.model._meta.object_name.lower(),
                    )
                to_field = new_apps.get_model(
                    *related_key
                )._meta.get_field_by_name(related_object.field.name)[0]
                schema_editor.alter_field(
                    model,
                    related_object.field,
                    to_field,
                )

    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        self.old_app_label, app_label = app_label, self.old_app_label
        self.database_forwards(app_label, schema_editor, from_state, to_state)
        app_label, self.old_app_label = self.old_app_label, app_label

    def describe(self):
        return "Move %s from %s" % (self.name, self.old_app_label)


class Migration(migrations.Migration):

    dependencies = [
       ('dst_app', 'XXX0_dst_app_old'),
       ('src_app', 'XXX0_src_app_old'),
    ]

    operations = [
        MoveModelFromOtherApp('MoveMe', 'src_app'),
    ]

Adicione dependência de XXX1_dst_app_newpara XXX1_src_app_new. XXX1_src_app_newé uma migração não operacional que é necessária para garantir que futuras src_appmigrações sejam executadas depois XXX1_dst_app_new.

Mover MoveMede src_app/models.pypara dst_app/models.py. Então corra:

python manage.py migrate

Isso é tudo!


Note que este código provavelmente é útil apenas para o django 1.7. Tentar isso no django 2.0 não funcionará. Isso também significa que o uso desse mecanismo para mover modelos adiciona uma sobrecarga de manutenção à atualização da sua versão do django.
Paul in 't Hout

0

Você pode tentar o seguinte (não testado):

  1. mova o modelo de src_appparadest_app
  2. migrar dest_app; verifique se a migração do esquema depende da src_appmigração mais recente ( https://docs.djangoproject.com/en/dev/topics/migrations/#migration-files )
  3. adicionar uma migração de dados para dest_app, que copia todos os dados desrc_app
  4. migrar src_app; verifique se a migração do esquema depende da migração mais recente (dados) de dest_app- ou seja: a migração da etapa 3

Observe que você copiará a tabela inteira, em vez de movê- la, mas dessa maneira os dois aplicativos não precisam tocar em uma tabela que pertence ao outro aplicativo, o que eu acho mais importante.


0

Digamos que você esteja movendo o modelo TheModel de app_a para app_b.

Uma solução alternativa é alterar as migrações existentes manualmente. A ideia é que sempre que você vir uma operação alterando o TheModel nas migrações do app_a, copie essa operação para o final da migração inicial do app_b. E cada vez que você vê uma referência 'app_a.TheModel' nas migrações de app_a, você a altera para 'app_b.TheModel'.

Acabei de fazer isso em um projeto existente, onde queria extrair um determinado modelo para um aplicativo reutilizável. O procedimento correu bem. Eu acho que as coisas seriam muito mais difíceis se houvesse referências de app_b para app_a. Além disso, eu tinha um Meta.db_table definido manualmente para o meu modelo, o que poderia ter ajudado.

Notavelmente, você terá um histórico de migração alterado. Isso não importa, mesmo se você tiver um banco de dados com as migrações originais aplicadas. Se as migrações original e reescrita terminarem com o mesmo esquema de banco de dados, essa reescrita deverá estar OK.


0
  1. altere os nomes dos modelos antigos para 'model_name_old'
  2. migrações
  3. crie novos modelos chamados 'model_name_new' com relacionamentos idênticos nos modelos relacionados (por exemplo, o modelo do usuário agora possui user.blog_old e user.blog_new)
  4. migrações
  5. escreva uma migração customizada que migra todos os dados para as novas tabelas de modelo
  6. teste essas migrações, comparando backups com novas cópias de banco de dados antes e depois da execução das migrações
  7. quando tudo estiver satisfatório, exclua os modelos antigos
  8. migrações
  9. altere os novos modelos para o nome correto 'model_name_new' -> 'model_name'
  10. testar toda a enorme quantidade de migrações em um servidor intermediário
  11. desligue o site de produção por alguns minutos para executar todas as migrações sem que os usuários interfiram

Faça isso individualmente para cada modelo que precisa ser movido. Eu não sugeriria fazer o que a outra resposta diz mudando para números inteiros e retornando para chaves estrangeiras. Há uma chance de que novas chaves estrangeiras sejam diferentes e linhas possam ter IDs diferentes após as migrações e eu não queria correr nenhum risco de IDs incompatíveis ao voltar para chaves estrangeiras.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.