如果Django中已经存在某些表,如何强制迁移到数据库? [英] How to force migrations to a DB if some tables already exist in Django?

查看:145
本文介绍了如果Django中已经存在某些表,如何强制迁移到数据库?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Python/Django proyect.由于一些回滚和其他混合因素,我们最终陷入了一种奇怪的情况.

I have a Python/Django proyect. Due to some rolls back, and other mixed stuff we ended up in a kind of odd scenario.

当前情况如下:

  • 数据库具有正确的表
  • 无法回滚或删除数据库
  • 代码是最新的

  • DB has the correct tables
  • DB can't be rolled back or dropped
  • Code is up to date

迁移文件夹位于数据库的 . (这些迁移是从其他地方进行的,不再存在其他地方")

Migrations folder is behind the DB by one or two migrations. (These migrations were applied from somewhere else and that "somewhere else" doesn't exist anymore)

我添加和更改了一些模型

I add and alter some models

我需要什么:

为了能够运行迁移并忽略"现有表并应用新表.或任何其他实现此目的的方法.

To be able to run the migrations and kind of "ignore" the existing tables and apply the new ones. Or any alternative way to achieve this.

有可能吗?

推荐答案

应用迁移时,Django在名为django_migrations的表中插入一行.这是Django知道哪些迁移已经被应用,哪些迁移没有被应用的唯一方法.因此,该表中的行必须与您的migrations目录中的文件匹配.如果您在应用迁移文件后丢失了它们,或者做了其他任何使事情不同步的事情,您就会遇到问题..因为数据库中的迁移号所引用的迁移文件与项目中的迁移文件是不同的.

When you apply a migration, Django inserts a row in a table called django_migrations. That's the only way Django knows which migrations have been applied already and which have not. So the rows in that table have to match the files in your migrations directory. If you've lost the migration files after they were applied, or done anything else to get things out of sync, you'll have problems.. because the migration numbers in your database refer to different migration files than the ones in your project.

因此,在执行其他任何操作之前,需要通过删除丢失或无法找回的所有迁移文件的django_migrations表行来使事情恢复同步. 该表应仅包含您确实拥有且已正确应用于数据库的那些迁移的行.

So before you do anything else, you need to bring things back into sync by deleting the django_migrations table rows for any migration files that you've lost somehow and can't get back. The table should contain rows for only those migrations that you do have and that were actually applied to the database correctly.

现在,您需要处理Django迁移不知道的数据库中的所有更改.为此,有一些选择:

Now you need to deal with any changes in your database that Django Migrations doesn't know about.. and for that there are a few options:

如果解决的问题使得已应用于数据库的数据库更改与未迁移的文件位于不同的迁移文件中,则可以通过使用--fake一次运行一次迁移来解决此问题.数据库中实际上已经存在的任何更改的选项.伪选项仅将行写到django_migrations表中,将迁移标记为已完成.仅当数据库实际上已经具有该迁移文件中包含的所有更改时,才执行此操作.

If things worked out such that the database changes that were already applied to the database are in different migration files than the ones that weren't, then you can fix it by running your migrations one at a time using the --fake option on any changes that are in reality already in the database. The fake option just writes the row to the django_migrations table marking the migration as done. Only do this if the database does in fact already have all the changes contained in that migration file.

,那些仅包含尚未应用到数据库的更改的迁移文件,将在不使用--fake选项的情况下运行,并且Django将应用它们.例如:

And those migration files that contain only changes which have not been applied to the database, run without the --fake option and Django will apply them. eg:

# database already has it
manage.py migrate myapp 0003 --fake 
# need it
manage.py migrate myapp 0004
# database already has it
manage.py migrate myapp 0005 --fake

如果您的迁移文件已应用了部分但不是全部更改,那么您将遇到更大的问题.在这种情况下,有几种解决方法(仅选择一种):

If you have migration files where some but not all of the changes have been applied, then you have a bigger problem. In that case, there are several ways to go about it (choose ONLY ONE):

  1. 编辑迁移文件,以将已经应用的更改(Django进行还是手动进行无关紧要)放入数量较少的迁移中,并将您需要做的一切放入数量较大的文件中.现在,您可以--fake编号较小的编号,并正常运行编号较高的编号.假设您对模型进行了10次更改,其中5次更改实际上已经存在于数据库中,但是Django不知道这些更改..因此,当您运行makemigrations时,将创建所有10个更改的新迁移变化.通常这将失败,因为数据库服务器无法添加例如已存在的列.将这些已应用的更改从新的迁移文件中移至先前(已应用)的迁移文件中.然后,Django将假定这些是在以前的迁移中应用的,并且不会尝试再次应用它们.然后,您可以照常migrate并应用新的更改.

  1. Edit the migration files to put changes that have already been applied (whether Django did it or you did it manually does not matter) into lower number migrations, and put everything you need done into higher numbered files. Now you can --fake the lower number ones, and run the higher numbered ones as normal. Let's say you have 10 changes you made to your models, and 5 of those changes are actually in the database already, but Django doesn't know about them.. so when you run makemigrations, a new migration is created with all 10 changes. This will normally fail because the database server can't for example add a column that already exists. Move these already-applied changes out of your new migration file, into the previous (already applied) migration file. Django will then assume that these were applied with the previous migration and will not try to apply them again. You can then migrate as normal and the new changes will be applied.

如果您不想触摸旧的迁移文件,一种更清洁的方法是先运行makemigrations --empty appname创建一个空的迁移文件.然后运行makemigrations,它将创建另一个迁移,其中包含Django认为需要完成的所有更改.将已经完成的迁移从该文件移动到您创建的空迁移中.然后--fake该迁移.这将使Django对数据库外观的了解与现实保持同步,然后您可以像往常一样migrate,将更改应用到上一个迁移文件中.

If you don't want to touch your older migration file, a cleaner way to do this is to first run makemigrations --empty appname to create an empty migration file. Then run makemigrations which will create another migration with all the changes that Django thinks need to be done. Move the already done migrations from that file into the empty migration you created.. then --fake that one. This will put Django's understanding of what the database looks like will be in sync with reality and you can then migrate as normal, applying the changes in the last migration file.

摆脱您刚刚使用makemigrations创建的所有新迁移.现在,注释掉或放回模型中尚未应用到数据库的所有内容,使您的代码与数据库中的实际内容匹配.现在,您可以执行makemigrationsmigrate appname --fake,您将使一切恢复同步.然后取消注释新代码并正常运行'makemigrations',然后运行migrate,更改将被应用.如果更改很小(例如,添加一些字段),则有时这是最简单的.如果变化很大,那不是...

Get rid of any new migrations you just created using makemigrations. Now, comment out or put back anything in your models that has not been applied to the database, leaving your code matching what's actually in the database. Now you can do makemigrations and migrate appname --fake and you will get things back in sync. Then uncomment your new code and run 'makemigrations' then migrate as normal and the changes will be applied. If the changes are small (for example, adding a few fields), sometimes this is easiest. If the changes are large, it isn't....

您可以继续(认真)自己对数据库进行更改,以使数据库保持最新状态.现在只需运行migrate --fake,如果您不搞砸,那么一切都会好起来的.再次,对于较小的更改这很容易,对于复杂的更改则不那么容易.

You can go ahead and (carefully) make the database changes yourself, bringing the database up to date. Now just run migrate --fake and if you didn't mess up then everything will be ok. Again, this is easy for smaller changes, not as easy for complicated ones.

您可以运行manage.py sqlmigrate > mychanges.sql.这将生成mychanges.sql,其中包含对数据库执行的所有SQL Django WOULD.现在,编辑该文件以删除已应用的所有更改,剩下需要做的事情.使用pgadminpsql执行该SQL(我希望您使用的是postgresql).现在所有更改都已完成..因此您可以运行manage.py migrate --fake,这将使Django与现实保持同步,并且您应该已经准备就绪.如果您的SQL技能足够,那么这可能是最直接的解决方案.

You can run manage.py sqlmigrate > mychanges.sql. This generates mychanges.sql containing all the SQL Django WOULD have executed against the database. Now edit that file to remove any changes that have already been applied, leaving what needs to be done. Execute that SQL using pgadmin or psql (you're using postgresql I hope). Now the changes have all been made.. so you can run manage.py migrate --fake, this will bring Django into sync with reality and you should be all set. If your SQL skills are sufficient, this is probably the most straightforward solution.

我应该添加两个警告:

首先,如果您应用了以后的迁移,例如0003_foobar.py,然后事情没有解决,您决定尝试回去并应用0002_bazbuz.py,那么Django将会从您的数据库中删除文件.例如,您可能已在0003中添加的列及其数据将被删除.既然您说不会丢失数据,那么回去时要非常小心.

First, if you apply a later migration, eg 0003_foobar.py, and then things don't work out and you decide to try going back and apply 0002_bazbuz.py, then Django will TAKE STUFF OUT OF YOUR DATABASE. For example a column you might have added in 0003 will be dropped along with its data. Since you say you can't lose data, be very careful about going back.

第二,不要急于运行--fake迁移.确保要伪造的整个迁移实际上已经在数据库中.否则,它变得非常混乱.如果您确实对伪造迁移感到后悔并且不想回滚,则可以通过从django_migrations表中删除该行来消除django对伪造迁移的了解.如果您了解自己在做什么,可以这样做.如果您知道确实没有应用迁移,那就可以了.

Second, do not rush into running --fake migrations. Make sure that the entire migration you are about to fake is actually in the database already. Else it gets very confusing. If you do regret faking migrations and don't want to roll back, you can erase django's knowledge of the faked migration by deleting that row from the django_migrations table. It is ok to do this.. if you understand what you are doing. If you know that the migration really was not applied, then it's ok.

这篇关于如果Django中已经存在某些表,如何强制迁移到数据库?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆