如果Django中已存在某些表,如何强制迁移到数据库?

时间:2021-05-20 18:04:10

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

我有一个Python / Django项目。由于一些回滚,以及其他混合的东西,我们最终出现了一种奇怪的情况。

The current scenario is like this:

目前的情况是这样的:

  • DB has the correct tables
  • DB具有正确的表
  • DB can't be rolled back or dropped
  • DB无法回滚或删除
  • 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

    我添加和更改了一些模型

  • I run makemigrations
  • 我运行makemigrations
  • New migrations are created, but it's a mix of new tables and some tables that already exist in the DB.
  • 创建了新的迁移,但它是新表和DB中已存在的一些表的混合。
  • If I run migrate it will complain that some of the tables that I'm trying to create already exist.
  • 如果我运行迁移,它会抱怨我正在尝试创建的某些表已经存在。

What I need:

我需要的:

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.

为了能够运行迁移,可以“忽略”现有表并应用新表。或任何替代方法来实现这一目标。

Is that possible?

那可能吗?

1 个解决方案

#1


11  

When you apply migrations, Django stores the fact that it applied each migration in a table called django_migrations. The entries in that table have to match 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会存储它在名为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_migrations表行来恢复同步,因为您丢失了以某种方式丢失的任何迁移文件。该表应包含仅用于您具有的并且实际上已正确应用于数据库的那些迁移的行。

Now you need to deal with the changes that migrations doesn't know about.. and for that there are a few options:

现在您需要处理迁移不了解的更改..为此,有几个选项:

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_migrations表,标记迁移已完成。只有在数据库确实已经包含该迁移文件中包含的所有更改时才执行此操作。

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:

那些仅包含未应用于数据库的更改的迁移文件,在没有--fake选项和Django的情况下运行将应用它们。例如:

# 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. Edit the migration files to put everything that has been applied already (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 it, so when you run makemigrations, a new migration is created with all 10 changes. You can then take the changes that were already made out of the new migration file, move them into the previous (already applied) migration file.. then apply only the new migration file. If you don't want to touch your older migration, you can first do makemigrations --empty appname to create an empty migration first. Then run makemigrations which will create another migration with all the changes. Move the already done migrations into the empty migration you created.. then --fake that one. Now django's understanding of what the database looks like will be in sync with reality and you can migrate as normal, applying the changes in the last migration file.

    编辑迁移文件,将已经应用的所有内容(无论是django是否已经完成,或者手动完成无关紧要)放入较低数量的迁移,并将您需要完成的所有内容放入更高编号的文件中。现在你可以 - 伪造较低的数字,并正常运行较高编号的那些。假设您对模型进行了10次更改,其中5次更改实际上已在数据库中,但django不知道,因此当您运行makemigrations时,将创建包含所有10个更改的新迁移。然后,您可以执行已从新迁移文件中进行的更改,将它们移动到先前(已应用的)迁移文件中。然后仅应用新的迁移文件。如果您不想触及较旧的迁移,可以先执行makemigrations --empty appname以首先创建空迁移。然后运行makemigrations,这将创建包含所有更改的另一个迁移。将已完成的迁移移动到您创建的空迁移中。然后 - 执行该迁移。现在,django对数据库外观的理解将与现实同步,您可以正常迁移,应用上一个迁移文件中的更改。

  2. 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....

    摆脱使用makemigrations创建的任何新迁移。现在,注释掉或放回模型中尚未应用于数据库的任何内容,使代码与数据库中的实际内容相匹配。现在你可以做makemigrations并迁移appname --fake,你会恢复同步。然后取消注释新代码并运行“makemigrations”,然后正常迁移,将应用更改。如果更改很小(例如,添加几个字段),有时这是最简单的。如果变化很大,那就不是......

  3. 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.

    您可以继续(小心)自己更改数据库,使数据库保持最新状态。现在只需运行migrate --fake,如果你没有搞砸,那么一切都会好的。同样,这对于较小的更改很容易,对于复杂的更改则不容易。

  4. 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.

    您可以运行manage.py sqlmigrate> mychanges.sql。这将生成mychanges.sql,其中包含针对数据库执行的所有SQL Django WOULD。现在编辑该文件以删除已经应用的任何更改,留下需要完成的任务。使用pgadmin或psql执行该SQL(我希望使用postgresql)。现在所有的更改都已完成..所以你可以运行manage.py migrate --fake,这将使Django与现实同步,你应该全部设置。如果您的SQL技能足够,这可能是最直接的解决方案。

I should add two warnings:

我应该添加两个警告:

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.

首先,如果您应用稍后的迁移,例如0003_foobar.py,然后事情无法解决,您决定尝试返回并应用0002_bazbuz.py,那么Django将从您的数据库中取出。例如,您可能在0003中添加的列将与其数据一起删除。既然你说你不能丢失数据,那就回去吧。

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_migrations表中删除该行来删除django对伪造迁移的了解。这样做是可以的..如果你明白自己在做什么。如果您知道迁移确实没有应用,那就没关系。

#1


11  

When you apply migrations, Django stores the fact that it applied each migration in a table called django_migrations. The entries in that table have to match 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会存储它在名为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_migrations表行来恢复同步,因为您丢失了以某种方式丢失的任何迁移文件。该表应包含仅用于您具有的并且实际上已正确应用于数据库的那些迁移的行。

Now you need to deal with the changes that migrations doesn't know about.. and for that there are a few options:

现在您需要处理迁移不了解的更改..为此,有几个选项:

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_migrations表,标记迁移已完成。只有在数据库确实已经包含该迁移文件中包含的所有更改时才执行此操作。

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:

那些仅包含未应用于数据库的更改的迁移文件,在没有--fake选项和Django的情况下运行将应用它们。例如:

# 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. Edit the migration files to put everything that has been applied already (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 it, so when you run makemigrations, a new migration is created with all 10 changes. You can then take the changes that were already made out of the new migration file, move them into the previous (already applied) migration file.. then apply only the new migration file. If you don't want to touch your older migration, you can first do makemigrations --empty appname to create an empty migration first. Then run makemigrations which will create another migration with all the changes. Move the already done migrations into the empty migration you created.. then --fake that one. Now django's understanding of what the database looks like will be in sync with reality and you can migrate as normal, applying the changes in the last migration file.

    编辑迁移文件,将已经应用的所有内容(无论是django是否已经完成,或者手动完成无关紧要)放入较低数量的迁移,并将您需要完成的所有内容放入更高编号的文件中。现在你可以 - 伪造较低的数字,并正常运行较高编号的那些。假设您对模型进行了10次更改,其中5次更改实际上已在数据库中,但django不知道,因此当您运行makemigrations时,将创建包含所有10个更改的新迁移。然后,您可以执行已从新迁移文件中进行的更改,将它们移动到先前(已应用的)迁移文件中。然后仅应用新的迁移文件。如果您不想触及较旧的迁移,可以先执行makemigrations --empty appname以首先创建空迁移。然后运行makemigrations,这将创建包含所有更改的另一个迁移。将已完成的迁移移动到您创建的空迁移中。然后 - 执行该迁移。现在,django对数据库外观的理解将与现实同步,您可以正常迁移,应用上一个迁移文件中的更改。

  2. 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....

    摆脱使用makemigrations创建的任何新迁移。现在,注释掉或放回模型中尚未应用于数据库的任何内容,使代码与数据库中的实际内容相匹配。现在你可以做makemigrations并迁移appname --fake,你会恢复同步。然后取消注释新代码并运行“makemigrations”,然后正常迁移,将应用更改。如果更改很小(例如,添加几个字段),有时这是最简单的。如果变化很大,那就不是......

  3. 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.

    您可以继续(小心)自己更改数据库,使数据库保持最新状态。现在只需运行migrate --fake,如果你没有搞砸,那么一切都会好的。同样,这对于较小的更改很容易,对于复杂的更改则不容易。

  4. 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.

    您可以运行manage.py sqlmigrate> mychanges.sql。这将生成mychanges.sql,其中包含针对数据库执行的所有SQL Django WOULD。现在编辑该文件以删除已经应用的任何更改,留下需要完成的任务。使用pgadmin或psql执行该SQL(我希望使用postgresql)。现在所有的更改都已完成..所以你可以运行manage.py migrate --fake,这将使Django与现实同步,你应该全部设置。如果您的SQL技能足够,这可能是最直接的解决方案。

I should add two warnings:

我应该添加两个警告:

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.

首先,如果您应用稍后的迁移,例如0003_foobar.py,然后事情无法解决,您决定尝试返回并应用0002_bazbuz.py,那么Django将从您的数据库中取出。例如,您可能在0003中添加的列将与其数据一起删除。既然你说你不能丢失数据,那就回去吧。

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_migrations表中删除该行来删除django对伪造迁移的了解。这样做是可以的..如果你明白自己在做什么。如果您知道迁移确实没有应用,那就没关系。