Estou planejando renomear vários modelos em um projeto existente do Django, onde existem muitos outros modelos que têm relacionamentos de chave estrangeira com os modelos que gostaria de renomear. Estou bastante certo de que isso exigirá várias migrações, mas não tenho certeza do procedimento exato.
Digamos que eu comece com os seguintes modelos em um aplicativo Django chamado myapp
:
class Foo(models.Model):
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_ridonkulous = models.BooleanField()
Quero renomear o Foo
modelo porque o nome realmente não faz sentido e está causando confusão no código, e Bar
tornaria um nome muito mais claro.
Pelo que li na documentação de desenvolvimento do Django, estou assumindo a seguinte estratégia de migração:
Passo 1
Modificar models.py
:
class Bar(models.Model): # <-- changed model name
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
foo = models.ForeignKey(Bar) # <-- changed relation, but not field name
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Bar) # <-- changed relation, but not field name
is_ridonkulous = models.BooleanField()
Observe que o AnotherModel
nome do campo para foo
não muda, mas a relação é atualizada para o Bar
modelo. Meu raciocínio é que eu não deveria mudar muito de uma só vez e que se eu alterasse esse nome de campo, bar
correria o risco de perder os dados nessa coluna.
Passo 2
Crie uma migração vazia:
python manage.py makemigrations --empty myapp
etapa 3
Edite a Migration
classe no arquivo de migração criado na etapa 2 para adicionar a RenameModel
operação à lista de operações:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.RenameModel('Foo', 'Bar')
]
Passo 4
Aplique a migração:
python manage.py migrate
Etapa 5
Edite os nomes dos campos relacionados em models.py
:
class Bar(models.Model):
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
bar = models.ForeignKey(Bar) # <-- changed field name
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
bar = models.ForeignKey(Bar) # <-- changed field name
is_ridonkulous = models.BooleanField()
Etapa 6
Crie outra migração vazia:
python manage.py makemigrations --empty myapp
Etapa 7
Edite a Migration
classe no arquivo de migração criado na etapa 6 para adicionar as RenameField
operações de qualquer nome de campo relacionado à lista de operações:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0002_rename_fields'), # <-- is this okay?
]
operations = [
migrations.RenameField('AnotherModel', 'foo', 'bar'),
migrations.RenameField('YetAnotherModel', 'foo', 'bar')
]
Etapa 8
Aplique a 2ª migração:
python manage.py migrate
Além de atualizar o restante do código (visualizações, formulários etc.) para refletir os novos nomes de variáveis, é basicamente assim que a nova funcionalidade de migração funcionaria?
Além disso, isso parece ter muitos passos. As operações de migração podem ser condensadas de alguma maneira?
Obrigado!
fonte
apps.get_model
-los. Levei muito tempo para descobrir isso../manage.py makemigrations myapp
comando perguntará se você renomeou o seu modelo. Por exemplo: você renomeou o modelo myapp.Foo para Bar? [s / N] Se você responder 's', a sua migração conterá asmigration.RenameModel('Foo', 'Bar')
mesmas contagens para os campos renomeados :-)manage.py makemigrations myapp
ainda pode falhar: "Talvez seja necessário adicionar manualmente isso se você alterar o nome do modelo e alguns de seus campos de uma só vez; para o detector automático, será como se você tivesse excluído um modelo com o nome antigo e adicionado um novo com um nome diferente e a migração criada perderá todos os dados da tabela antiga ". Docs do Django 2.1 Para mim, foi suficiente criar uma migração vazia, adicionar o nome do modelo a ela e executarmakemigrations
como de costume.No começo, pensei que o método de Fiver funcionou para mim porque a migração funcionou bem até a etapa 4. No entanto, as alterações implícitas 'ForeignKeyField (Foo)' em 'ForeignKeyField (Bar)' não estavam relacionadas em nenhuma migração. É por isso que a migração falhou quando eu quis renomear os campos de relacionamento (etapa 5-8). Isso pode ser devido ao fato de que meu 'AnotherModel' e 'YetAnotherModel' são despachados em outros aplicativos no meu caso.
Então, consegui renomear meus modelos e campos de relacionamento, seguindo as etapas abaixo:
Eu adaptei o método a partir disso e, particularmente, o truque do otranzer.
Então, como o Fiver, digamos que temos no myapp :
E em myotherapp :
Passo 1:
Transforme todos os OneToOneField (Foo) ou ForeignKeyField (Foo) em IntegerField (). (Isso manterá o ID do objeto Foo relacionado como valor do campo inteiro).
Então
Etapa 2: (como a etapa 2-4 do Fiver)
Alterar o nome do modelo
Crie uma migração vazia:
Em seguida, edite-o como:
Eventualmente
Etapa 3:
Transforme seu IntegerField () de volta no ForeignKeyField ou OneToOneField anterior, mas com o novo Modelo de Barras. (O campo inteiro anterior estava armazenando o ID, então o django entenda isso e restabeleça a conexão, o que é legal.)
Então faça:
Muito importante, nesta etapa, você deve modificar todas as novas migrações e adicionar a dependência nas migrações RenameModel Foo-> Bar. Portanto, se o AnotherModel e o YetAnotherModel estiverem no myotherapp, a migração criada no myotherapp deverá ser assim:
Então
Passo 4:
Eventualmente, você pode renomear seus campos
e depois renomeie automaticamente
(o django deve perguntar se você realmente renomeou o nome do modelo, diga sim)
E é isso!
Isso funciona no Django1.8
fonte
IntegerField
. Isso funcionou perfeitamente para mim e tem a vantagem adicional de serem recriados com o nome correto. Naturalmente, eu recomendaria revisar todas as migrações antes de executá-las!ForeignKey
s paraIntegerField
s salvou meu dia hoje!Eu precisava fazer a mesma coisa e seguir. Mudei o modelo de uma só vez (etapas 1 e 5 juntas da resposta de Fiver). Em seguida, criou uma migração de esquema, mas a editou para ser esta:
Isso funcionou perfeitamente. Todos os meus dados existentes apareceram, todas as outras tabelas mencionadas Bar bem.
daqui: https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/
fonte
No Django 1.10, consegui alterar dois nomes de classe de modelo (incluindo uma ForeignKey e com dados) executando simplesmente Makemigrations e depois Migrate para o aplicativo. Para a etapa Makemigrations, tive que confirmar que desejava alterar os nomes das tabelas. Migrate alterou os nomes das tabelas sem problemas.
Em seguida, alterei o nome do campo ForeignKey para corresponder e novamente fui solicitado pelos Makemigrations para confirmar que queria alterar o nome. Migre do que fez a alteração.
Então, tomei isso em duas etapas, sem nenhuma edição especial de arquivo. No início, eu recebi erros porque esqueci de alterar o arquivo admin.py, conforme mencionado por @wasibigeek.
fonte
Também enfrentei o problema como v.thorey descreveu e descobriu que sua abordagem é muito útil, mas pode ser condensada em menos etapas, que são realmente as etapas de 5 a 8, conforme Fiver descreveu sem as etapas de 1 a 4, exceto que a etapa 7 precisa ser alterada, pois abaixo da etapa 3. As etapas gerais são as seguintes:
Etapa 1: edite os nomes dos campos relacionados em models.py
Etapa 2: criar uma migração vazia
Etapa 3: Edite a classe Migration no arquivo de migração criado na Etapa 2
Etapa 4: aplicar a migração
Feito
PS Eu tentei essa abordagem no Django 1.9
fonte
Estou usando o Django versão 1.9.4
Eu segui os seguintes passos: -
Acabei de renomear o modelo oldName para NewName Run
python manage.py makemigrations
. Ele solicitará que vocêDid you rename the appname.oldName model to NewName? [y/N]
selecione YCorra
python manage.py migrate
e ele solicitaráOs seguintes tipos de conteúdo são antigos e precisam ser excluídos:
Quaisquer objetos relacionados a esses tipos de conteúdo por uma chave estrangeira também serão excluídos. Tem certeza de que deseja excluir esses tipos de conteúdo? Se não tiver certeza, responda 'não'.
Renomeie e migre todos os dados existentes para uma nova tabela nomeada para mim.
fonte
Infelizmente, encontrei problemas (cada django 1.x) com a renomeação da migração, deixando nomes de tabelas antigos no banco de dados.
O Django nem tenta nada na mesa antiga, apenas renomeia o seu próprio modelo. O mesmo problema com chaves estrangeiras e índices em geral - as alterações não são rastreadas corretamente pelo Django.
A solução mais simples (solução alternativa):
A solução real (uma maneira fácil de alternar todos os índices, restrições, gatilhos, nomes etc. em 2 confirmações, mas em tabelas menores ):
confirmar A:
Bar
. (incluindo todas as relações no esquema)Na migração
RunPython
, prepare , que copia dados de Foo para Bar (incluindoid
Foo)confirmar B: (sem pressa, faça-o quando uma equipe inteira for migrada)
Foo
limpeza adicional:
bug no Django:
fonte
Só queria confirmar e adicionar um comentário ceasaro. O Django 2.0 parece fazer isso automaticamente agora.
Estou no Django 2.2.1, tudo o que tive que fazer para renomear o modelo e executar
makemigrations
.Aqui ele pergunta se eu havia renomeado a classe específica de
A
paraB
, eu escolhi yes e executei migrate e tudo parece funcionar.Nota: eu não renomeei o nome do modelo antigo em nenhum arquivo dentro da pasta projeto / migrações.
fonte
Eu precisava renomear algumas tabelas. Mas apenas uma renomeação de modelo foi notada pelo Django. Isso aconteceu porque o Django repete os modelos adicionados e removidos. Para cada par, ele verifica se eles são do mesmo aplicativo e têm campos idênticos . Apenas uma tabela não tinha chaves estrangeiras para as tabelas a serem renomeadas (chaves estrangeiras contêm o nome da classe do modelo, como você se lembra). Em outras palavras, apenas uma tabela não teve alterações de campo. Por isso foi notado.
Portanto, a solução é renomear uma tabela por vez, alterando o nome da classe do modelo e
models.py
, possivelmenteviews.py
, fazendo uma migração. Depois disso, inspecione seu código em busca de outras referências (nomes de classe de modelo, nomes relacionados (consulta), nomes de variáveis). Faça uma migração, se necessário. Em seguida, combine opcionalmente todas essas migrações em uma (certifique-se de copiar também as importações).fonte
Eu faria palavras @ceasaro, minhas no seu comentário sobre esta resposta .
Versões mais recentes do Django podem detectar mudanças e perguntar sobre o que foi feito. Eu também acrescentaria que o Django pode misturar a ordem de execução de alguns comandos de migração.
Seria sensato para aplicar pequenas mudanças e correr
makemigrations
emigrate
e se o erro ocorrer o arquivo de migração podem ser editados.Algumas linhas de ordem de execução podem ser alteradas para evitar erros.
fonte
migrations.SeparateDatabaseAndState
pode ajudar?Se você estiver usando um bom IDE como PyCharm, poderá clicar com o botão direito do mouse no nome do modelo e refatorar -> renomear. Isso poupa o trabalho de analisar todo o seu código que faz referência ao modelo. Em seguida, execute makemigrations e migre. O Django 2+ simplesmente confirmará a mudança de nome.
fonte
Atualizei o Django da versão 10 para a versão 11:
(
-U
para "atualização") e resolveu o problema.fonte