45

Using Django 1.7 migrations.

I accidentally dropped a table in my database. I assumed that by running migration again this would recreate the table but no, Django states "No migrations to apply".

How to I get Django to recreate the table?

I have run:

> makemigrations - No changes detected
> migrate - No migrations to apply.

I have tried making a change to the model and running a new migration and it simply states that "Table 'x.test_customer' doesn't exist" which is correct, but what I was hoping it that it would recreate the table.

Prometheus
  • 32,405
  • 54
  • 166
  • 302

10 Answers10

65

Go to your database and find the table django_migrations. Delete all the rows which have app equals your app name.

Then do a makemigrations & migrate will work.

J.Q
  • 669
  • 1
  • 6
  • 6
  • 2
    this is more convenient than the accepted answer of creating a manual migration – hoju Oct 11 '16 at 04:50
  • 3
    This might be dangerous if you have dependencies between apps in the migrations. – Risadinha Nov 09 '16 at 11:27
  • 1
    This worked well for me, thanks. I also had to delete from django_content_type where app_label = 'yourappname' and delete from auth_permission where content_type_id = one of the rows in the previous delete. – Robert Rapplean Nov 15 '18 at 06:08
26

Another solution I've found and works perfectly:

In django 1.7:

  1. Delete your migrations folder

  2. In the database: DELETE FROM django_migrations WHERE app = 'app_name'.

    You could alternatively just truncate this table.

  3. python manage.py makemigrations

  4. python manage.py migrate --fake

In django 1.9.5:

  1. Delete your migrations folder

  2. In the database: DELETE FROM django_migrations WHERE app = 'app_name'.

    You could alternatively just truncate this table.

  3. python manage.py makemigrations app_name

  4. python manage.py migrate

This works 100% for me!

Community
  • 1
  • 1
Raúl EL
  • 1,206
  • 11
  • 6
22

Migrations check for differences in your models, then translates that to actions, which are translated to SQL. It does not automatically sync the db scheme with your models, and it has no way of knowing you dropped a table (it doesn't know about manual changes because, well, you're not supposed to do manual changes. That's the point)

The answer? a manual change requires a manual migration as well. What you need to do is simply write your own migration and manually tell south to re-build the table. It's not very difficult, The docs make it pretty easy. Just make something like this:

from django.db import migrations, models

class Migration(migrations.Migration):

    operations = [
        migrations.CreateModel("Foo"),
        migrations.AddField("Foo", "bar", models.IntegerField(default=0))
    ] 

You can probably look into the first migration file (the one that made the model in the first place) and copy paste almost all of it. Then all you have to do is run the migration like you always do

yuvi
  • 18,155
  • 8
  • 56
  • 93
  • I see, that makes sense now. – Prometheus Nov 03 '14 at 11:39
  • Could this also work? http://stackoverflow.com/questions/25606879/how-to-migrate-back-from-initial-migration-in-django-1-7. Once removed, from the migration history you could try to do the makemigrations/migrate again. I don't know if this will crash when tables are already dropped... – argaen Nov 03 '14 at 11:43
  • @djangozone note that that clears and drops **all the tables** (which might also be ok, if it's a dev with no important data) – yuvi Nov 03 '14 at 11:44
  • 1
    Yeah, I usually use the dumpdata/loaddata combo which in my opinion is more straightforward than dealing with manual migrations.. Ofc, if you work with lots of data this is not the best way but not my case. – argaen Nov 03 '14 at 11:53
  • Good to know! Happy to have helped =] @djangozone really really depends on the project (and also personal preference). I think migrations are very straightforward, but I sometimes opt for complete reset as well when things get messy – yuvi Nov 03 '14 at 11:55
  • Migration does indeed check your schema (of course doesn't sync it automatically). It can detect very well for example if a migration was already run (seeing the added column/field), or detecting if you have change in the schema which is not covered with a migration. Probably the OP expected that the same thing will happen when a table is missing. – Csaba Toth Dec 29 '16 at 19:56
  • @CsabaToth Yeah you're right, it does make some checks, but it (a) doesn't sync automatically and (b) usually can't automatically decide what to do in case you make manual changes (because it assumes you won't make any). I think it's a good approach to use it as if it doesn't know anything, especially when you're pretty new – yuvi Dec 31 '16 at 21:01
7

I actually found an easier way to do this. You fake that you rollback what doesn't exist, then you re-migrate. If your migration 0005 was the one where it creates the table:

python manage.py migrate myapp --fake 0004
python manage.py migrate myapp

Should be good after that!

If you need to skip later ones, you do this:

python manage.py migrate myapp --fake 0004
python manage.py migrate myapp 0005
python manage.py migrate myapp --fake

Should be good after that!

johannestaas
  • 1,175
  • 1
  • 9
  • 15
  • for newer versions of django the command should be `python manage.py migrate --fake myapp 0004` where the app name is an argument to the --fake flag – grrrrrr Jan 19 '18 at 17:15
6

In my case in django 2.0.2 for recreating dropped table I needed to comment my models in myapp and then migrate with --fake and uncomment my models and migrate without --fake A little different from raul answer:

  1. Delete your migrations files in your desired app
  2. Thanks to raul answer: In the database: DELETE FROM django_migrations WHERE app = 'app_name'.
  3. comment codes in models.py and all this models usage in views, signals and etc (to prevent error).
  4. python manage.py makemigrations YOUR_APP_NAME
  5. python manage.py migrate --fake
  6. un-comment what you commented in step 3
  7. python manage.py makemigrations YOUR_APP_NAME
  8. migrate without --fake: python manage.py migrate

This should solve some users problem.

SirSaleh
  • 1,452
  • 3
  • 23
  • 39
3

Full disclaimer, this is a destructive operation in some cases, and I mostly use it to remigrate parts of the system without affecting the DB.

Have you tried doing it via the table django_migrations? Just remove the rows that map to the app label and the migration names in question and delete those rows.

+----+-----------------------+----------------------------------------------------------+---------------------+
| id | app                   | name                                                     | applied             |
+----+-----------------------+----------------------------------------------------------+---------------------+
|  1 | contenttypes          | 0001_initial                                             | 2015-03-07 16:32    |
| 30 | homepage              | 0001_initial                                             | 2015-04-02 13:30:44 |
| 31 | homepage              | 0002_auto_20150408_1751                                  | 2015-04-08 12:24:55 |
| 32 | homepage              | 0003_remove_mappinghomepagemoduleinventory_inventoryinfo | 2015-04-09 08:09:59 |
+----+-----------------------+----------------------------------------------------------+---------------------+

So now if i want to remove homepage, I can just delete row 30, 31, 32.

Of course since you dropped the tables too, you'd need to change django_content_type too:

+----+----------------------------------------+-----------------------+--------------------------------------+
| id | name                                   | app_label             | model                                |
+----+----------------------------------------+-----------------------+--------------------------------------+
|  1 | content type                           | contenttypes          | contenttype                          |
|  2 | session                                | sessions              | session                              |
|  3 | site                                   | sites                 | site                                 |
| 92 | master_homepagemodule_extrafields      | homepage              | masterhomepagemoduleextrafields      |
| 93 | mapping_homepagemodule_inventory       | homepage              | mappinghomepagemoduleinventory       |
| 94 | master_homepagemodule_inventoryfields  | homepage              | masterhomepagemoduleinventoryfields  |
| 95 | mapping_homepagemodule_inventoryfields | homepage              | mappinghomepagemoduleinventoryfields |
| 96 | master_homepagemodule                  | homepage              | masterhomepagemodule                 |
| 97 | mapping_homepagemodule_extrafields     | homepage              | mappinghomepagemoduleextrafields     |
+----+----------------------------------------+-----------------------+--------------------------------------+

So now you'd have to remove the tables that you need to remigrate need by dropping the rows for those tables.

I've used this when time was scarce and we needed a quick dirty fix, or when playing around in development.
Hope it helps you too!

kunl
  • 1,177
  • 1
  • 15
  • 25
  • Thanks to provide this dirty fix, it helps. In development stage, and delete a table, then can not go back. And after delete the related row in the django_migrations, I run "python manage.py migrate zero" to also clean/drop all the tables, then run "python manage.py migrate" to start over. – zhihong Apr 30 '15 at 14:07
2

The simplest way to do this on django >= 1.9 is to run the following:

./manage.py migrate app_name zero

That will remove your tables and revert all migrations.

yekta
  • 3,363
  • 3
  • 35
  • 50
2

Just ran into this while building a little app learning django. I wanted to create a non-null column for an existing table. There were three steps:

  1. drop the table
  2. remove the record in django_migrations
  3. remove the migration for the table in question
    • if you run "python manage.py makemigrations posts" before this step you still get the "You are trying to add a non-nullable field "

For an actual application you'd need to supply a default value as others have pointed out.

techbrownbags
  • 618
  • 5
  • 10
0

OK, so what I did was not to mess with migrations. Seems like I get in trouble every so often with migrations. And in this case, trying to replay migrations got me nowhere. Might not have helped that there were some South-vintage migrations as well as the newer 1.7 stuff.

environment: postgres 9.3

Basically, I restored an old backup of my database into an empty database. Then I brought up the restore target in the postgres admin utility and copy/pasted the create tables from each table's description (I had only 4 to go). Switched over to my test database & ran it in pg's sql utility.

I dunno, I don't think it is unreasonable to drop a table manually if you are having issues with it (looked to me as if my id field's sequence was not working), as long as you can live with losing your data. Migrations should be resilient in that use case.

JL Peyret
  • 10,917
  • 2
  • 54
  • 73
0

Probably the simplest way to do it.

  1. Make a copy of the migration file that you want to migrate and rename it as the latest migration file

e.g. if the file you want to migrate is app_name.002_xyz, and your latest migration file is app_name.004_abc

Then you need to make a copy of app_name.002_xyz and rename it as the latest migration file. For example, let's rename it to app_name.005_xyz

  1. Now add the recent latest as a dependency in this new file

e.g. add this line to the new migration file

class Migration(migrations.Migration):

    dependencies = [
        ('app_name', 'app_name.004_abc'),
    ]
    
    ...
  1. Migrate it

e.g. add this line to the new migration file

python manage.py migrate app_name
  1. Awesome, the new migrations are made and tables are recreated

e.g.

Running migrations:
Applying app_name.005_xyz...OK
  1. Delete the new migration file app_name.005_xyz and you're good!
OM Bharatiya
  • 1,840
  • 14
  • 23